Author: axel
Date: 2010-06-03 22:07:47 +0200 (Thu, 03 Jun 2010)
New Revision: 1683
Added:
trunk/bmx/
trunk/bmx/Makefile
trunk/bmx/allocate.c
trunk/bmx/allocate.h
trunk/bmx/avl.c
trunk/bmx/avl.h
trunk/bmx/bmx.c
trunk/bmx/bmx.h
trunk/bmx/control.c
trunk/bmx/control.h
trunk/bmx/cyassl/
trunk/bmx/cyassl/config.h
trunk/bmx/cyassl/misc.c
trunk/bmx/cyassl/misc.h
trunk/bmx/cyassl/sha.c
trunk/bmx/cyassl/sha.h
trunk/bmx/cyassl/types.h
trunk/bmx/hna.c
trunk/bmx/hna.h
trunk/bmx/iid.c
trunk/bmx/iid.h
trunk/bmx/lib/
trunk/bmx/lib/Makefile
trunk/bmx/lib/bmx_uci_config/
trunk/bmx/lib/bmx_uci_config/Makefile
trunk/bmx/lib/bmx_uci_config/uci_config.c
trunk/bmx/lib/bmx_uci_config/uci_config.h
trunk/bmx/list.c
trunk/bmx/list.h
trunk/bmx/msg.c
trunk/bmx/msg.h
trunk/bmx/plugin.c
trunk/bmx/plugin.h
trunk/bmx/route.c
trunk/bmx/route.h
trunk/bmx/schedule.c
trunk/bmx/schedule.h
Modified:
trunk/batman/Makefile
Log:
starting BMX-v0.4 development cycle, (incompatible with BatMan-eXperimental v0.3 branch)
Modified: trunk/batman/Makefile
===================================================================
--- trunk/batman/Makefile 2010-06-02 15:47:07 UTC (rev 1682)
+++ trunk/batman/Makefile 2010-06-03 20:07:47 UTC (rev 1683)
@@ -29,7 +29,7 @@
#NO_POLICY_ROUTING = -DNO_POLICY_ROUTING
CC = gcc
-CFLAGS += -pedantic -Wall -W -O1 -g3 -std=gnu99
+CFLAGS += -pedantic -Wall -W -Os -g3 -std=gnu99
EXTRA_CFLAGS = -DDEBUG_MALLOC -DMEMORY_USAGE -DPROFILE_DATA $(NO_POLICY_ROUTING)
-DREVISION_VERSION=$(REVISION_VERSION)
LDFLAGS += -lpthread
Added: trunk/bmx/Makefile
===================================================================
--- trunk/bmx/Makefile (rev 0)
+++ trunk/bmx/Makefile 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,168 @@
+# Copyright (C) 2010 BMX contributors:
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA
+
+REVISION_VERSION = 0$(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}';} 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 -DREVISION_VERSION=$(REVISION_VERSION)
-DDEBUG_MALLOC -DMEMORY_USAGE
+
+LDFLAGS += -Wl,-export-dynamic -ldl -g3 -lm
+
+#-lcyassl
+#LDFLAGS += -shared -lssl -lcrypto
+# -static
+# -pg
+
+
+#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
+
+# -DDEBUG_MALLOC + ~0k
+# -DMEMORY_USAGE + ~1k
+
+# 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
+
+# -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
+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
+
+
+all:
+ $(MAKE) $(BINARY_NAME)
+ # further make targets: help, libs, build_all, strip[_libs|_all], install[_libs|_all],
clean[_libs|_all]
+
+libs: all
+ $(MAKE) -C lib all CORE_CFLAGS='$(CFLAGS)'
+
+
+
+$(BINARY_NAME): $(OBJS) Makefile
+ $(CC) $(OBJS) -o $@ $(LDFLAGS) $(EXTRA_LDFLAGS)
+
+%.o: %.c %.h Makefile $(SRC_H)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+%.o: %.c Makefile $(SRC_H)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+
+strip: all
+ strip $(BINARY_NAME)
+
+strip_libs: all libs
+ $(MAKE) -C lib strip
+
+
+
+
+install: all
+ mkdir -p $(SBINDIR)
+ install -m 0755 $(BINARY_NAME) $(SBINDIR)
+
+install_libs: all
+ $(MAKE) -C lib install CORE_CFLAGS='$(CFLAGS)'
+
+
+
+clean:
+ rm -f $(BINARY_NAME) *.o posix/*.o linux/*.o cyassl/*.o
+
+clean_libs:
+ $(MAKE) -C lib clean
+
+
+clean_all: clean clean_libs
+build_all: all libs
+strip_all: strip strip_libs
+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
+
Added: trunk/bmx/allocate.c
===================================================================
--- trunk/bmx/allocate.c (rev 0)
+++ trunk/bmx/allocate.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2006 B.A.T.M.A.N. contributors:
+ * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "bmx.h"
+
+
+#define MAGIC_NUMBER 0x12345678
+
+#if defined DEBUG_MALLOC
+
+
+struct chunkHeader *chunkList = NULL;
+
+struct chunkHeader
+{
+ struct chunkHeader *next;
+ uint32_t length;
+ int32_t tag;
+ uint32_t magicNumber;
+};
+
+struct chunkTrailer
+{
+ uint32_t magicNumber;
+};
+
+
+
+#if defined MEMORY_USAGE
+
+struct memoryUsage *memoryList = NULL;
+
+
+struct memoryUsage
+{
+ struct memoryUsage *next;
+ uint32_t length;
+ uint32_t counter;
+ int32_t tag;
+};
+
+
+void addMemory( uint32_t length, int32_t tag ) {
+
+ struct memoryUsage *walker;
+
+ for ( walker = memoryList; walker != NULL; walker = walker->next ) {
+
+ if ( walker->tag == tag ) {
+
+ walker->counter++;
+ break;
+ }
+ }
+
+ if ( walker == NULL ) {
+
+ walker = malloc( sizeof(struct memoryUsage) );
+
+ walker->length = length;
+ walker->tag = tag;
+ walker->counter = 1;
+
+ walker->next = memoryList;
+ memoryList = walker;
+ }
+
+}
+
+
+void removeMemory( int32_t tag, int32_t freetag ) {
+
+ struct memoryUsage *walker;
+
+ for ( walker = memoryList; walker != NULL; walker = walker->next ) {
+
+ if ( walker->tag == tag ) {
+
+ if ( walker->counter == 0 ) {
+
+ dbg( DBGL_SYS, DBGT_ERR,
+ "Freeing more memory than was allocated: malloc tag = %d, free tag =
%d",
+ tag, freetag );
+ cleanup_all( -500069 );
+
+ }
+
+ walker->counter--;
+ break;
+
+ }
+
+ }
+
+ if ( walker == NULL ) {
+
+ dbg( DBGL_SYS, DBGT_ERR,
+ "Freeing memory that was never allocated: malloc tag = %d, free tag =
%d",
+ tag, freetag );
+ cleanup_all( -500070 );
+ }
+}
+
+#endif
+
+#if defined MEMORY_USAGE
+
+void debugMemory( struct ctrl_node *cn ) {
+
+ struct memoryUsage *memoryWalker;
+
+ dbg_printf( cn, "\nMemory usage information:\n" );
+
+ for ( memoryWalker = memoryList; memoryWalker != NULL; memoryWalker =
memoryWalker->next ) {
+
+ if ( memoryWalker->counter != 0 )
+ dbg_printf( cn, " tag: %4i, num malloc: %4i, bytes per malloc: %4i, total:
%6i\n",
+ memoryWalker->tag, memoryWalker->counter, memoryWalker->length,
+ memoryWalker->counter * memoryWalker->length );
+
+ }
+ dbg_printf( cn, "\n" );
+
+}
+
+#endif
+
+
+void checkIntegrity(void)
+{
+ struct chunkHeader *walker;
+ struct chunkTrailer *chunkTrailer;
+ unsigned char *memory;
+
+// dbgf_all(DBGT_INFO, " ");
+
+ for (walker = chunkList; walker != NULL; walker = walker->next)
+ {
+ if (walker->magicNumber != MAGIC_NUMBER)
+ {
+ dbgf( DBGL_SYS, DBGT_ERR,
+ "invalid magic number in header: %08x, malloc tag = %d",
+ walker->magicNumber, walker->tag );
+ cleanup_all( -500073 );
+ }
+
+ memory = (unsigned char *)walker;
+
+ chunkTrailer = (struct chunkTrailer *)(memory + sizeof(struct chunkHeader) +
walker->length);
+
+ if (chunkTrailer->magicNumber != MAGIC_NUMBER)
+ {
+ dbgf( DBGL_SYS, DBGT_ERR,
+ "invalid magic number in trailer: %08x, malloc tag = %d",
+ chunkTrailer->magicNumber, walker->tag );
+ cleanup_all( -500075 );
+ }
+ }
+
+}
+
+void checkLeak(void)
+{
+ struct chunkHeader *walker;
+
+ if ( chunkList != NULL ) {
+
+ openlog( "bmx", 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
);
+
+ }
+
+ closelog();
+ }
+
+}
+
+void *_debugMalloc(uint32_t length, int32_t tag) {
+
+ unsigned char *memory;
+ struct chunkHeader *chunkHeader;
+ struct chunkTrailer *chunkTrailer;
+ unsigned char *chunk;
+
+ memory = malloc(length + sizeof(struct chunkHeader) + sizeof(struct chunkTrailer));
+
+ if (memory == NULL)
+ {
+ dbg( DBGL_SYS, DBGT_ERR, "Cannot allocate %u bytes, malloc tag = %d",
+ (unsigned int)(length + sizeof(struct chunkHeader) + sizeof(struct chunkTrailer)),
tag );
+ cleanup_all( -500076 );
+ }
+
+ chunkHeader = (struct chunkHeader *)memory;
+ chunk = memory + sizeof(struct chunkHeader);
+ chunkTrailer = (struct chunkTrailer *)(memory + sizeof(struct chunkHeader) + length);
+
+ chunkHeader->length = length;
+ chunkHeader->tag = tag;
+ chunkHeader->magicNumber = MAGIC_NUMBER;
+
+ chunkTrailer->magicNumber = MAGIC_NUMBER;
+
+ chunkHeader->next = chunkList;
+ chunkList = chunkHeader;
+
+#if defined MEMORY_USAGE
+
+ addMemory( length, tag );
+
+#endif
+
+ return chunk;
+}
+
+void *_debugRealloc(void *memoryParameter, uint32_t length, int32_t tag) {
+
+ unsigned char *memory;
+ struct chunkHeader *chunkHeader=NULL;
+ struct chunkTrailer *chunkTrailer;
+ unsigned char *result;
+ uint32_t copyLength;
+
+ if (memoryParameter) { /* if memoryParameter==NULL, realloc() should work like malloc()
!! */
+ memory = memoryParameter;
+ chunkHeader = (struct chunkHeader *)(memory - sizeof(struct chunkHeader));
+
+ if (chunkHeader->magicNumber != MAGIC_NUMBER)
+ {
+ dbgf( DBGL_SYS, DBGT_ERR,
+ "invalid magic number in header: %08x, malloc tag = %d",
+ chunkHeader->magicNumber, chunkHeader->tag );
+ cleanup_all( -500078 );
+ }
+
+ chunkTrailer = (struct chunkTrailer *)(memory + chunkHeader->length);
+
+ if (chunkTrailer->magicNumber != MAGIC_NUMBER)
+ {
+ dbgf( DBGL_SYS, DBGT_ERR,
+ "invalid magic number in trailer: %08x, malloc tag = %d",
+ chunkTrailer->magicNumber, chunkHeader->tag );
+ cleanup_all( -500079 );
+ }
+ }
+
+
+ result = _debugMalloc(length, tag);
+ if (memoryParameter) {
+ copyLength = length;
+
+ if (copyLength > chunkHeader->length)
+ copyLength = chunkHeader->length;
+
+ memcpy(result, memoryParameter, copyLength);
+ debugFree(memoryParameter, -300000);
+ }
+
+ return result;
+}
+
+void _debugFree(void *memoryParameter, int tag) {
+
+ unsigned char *memory;
+ struct chunkHeader *chunkHeader;
+ struct chunkTrailer *chunkTrailer;
+ struct chunkHeader *walker;
+ struct chunkHeader *previous;
+
+ memory = memoryParameter;
+ chunkHeader = (struct chunkHeader *)(memory - sizeof(struct chunkHeader));
+
+ if (chunkHeader->magicNumber != MAGIC_NUMBER)
+ {
+ dbgf( DBGL_SYS, DBGT_ERR,
+ "invalid magic number in header: %08x, malloc tag = %d, free tag = %d",
+ chunkHeader->magicNumber, chunkHeader->tag, tag );
+ cleanup_all( -500080 );
+ }
+
+ previous = NULL;
+
+ for (walker = chunkList; walker != NULL; walker = walker->next)
+ {
+ if (walker == chunkHeader)
+ break;
+
+ previous = walker;
+ }
+
+ if (walker == NULL)
+ {
+ dbg( DBGL_SYS, DBGT_ERR, "Double free detected, malloc tag = %d, free tag =
%d",
+ chunkHeader->tag, tag );
+ cleanup_all( -500081 );
+ }
+
+ if (previous == NULL)
+ chunkList = walker->next;
+
+ else
+ previous->next = walker->next;
+
+
+ chunkTrailer = (struct chunkTrailer *)(memory + chunkHeader->length);
+
+ if (chunkTrailer->magicNumber != MAGIC_NUMBER)
+ {
+ dbgf( DBGL_SYS, DBGT_ERR,
+ "invalid magic number in trailer: %08x, malloc tag = %d, free tag =
%d",
+ chunkTrailer->magicNumber, chunkHeader->tag, tag );
+ cleanup_all( -500082 );
+ }
+
+#if defined MEMORY_USAGE
+
+ removeMemory( chunkHeader->tag, tag );
+
+#endif
+
+ free(chunkHeader);
+
+
+}
+
+#else
+
+void checkIntegrity(void)
+{
+}
+
+void checkLeak(void)
+{
+}
+
+void debugMemory( struct ctrl_node *cn )
+{
+}
+
+void *_debugMalloc(uint32_t length, int32_t tag)
+{
+ void *result;
+
+ result = malloc(length);
+
+ if (result == NULL)
+ {
+ dbg( DBGL_SYS, DBGT_ERR, "Cannot allocate %u bytes, malloc tag = %d", length,
tag );
+ cleanup_all( -500072 );
+ }
+
+ return result;
+}
+
+void *_debugRealloc(void *memory, uint32_t length, int32_t tag)
+{
+ void *result;
+
+ result = realloc(memory, length);
+
+ if (result == NULL) {
+ dbg( DBGL_SYS, DBGT_ERR, "Cannot re-allocate %u bytes, malloc tag = %d",
length, tag );
+ cleanup_all( -500071 );
+ }
+
+ return result;
+}
+
+void _debugFree(void *memory, int32_t tag)
+{
+ free(memory);
+}
+
+#endif
Added: trunk/bmx/allocate.h
===================================================================
--- trunk/bmx/allocate.h (rev 0)
+++ trunk/bmx/allocate.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 B.A.T.M.A.N. contributors:
+ * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+
+#ifndef _ALLOCATE_H
+#define _ALLOCATE_H 1
+#include <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) )
+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);
+
+void checkIntegrity(void);
+void checkLeak(void);
+void debugMemory( struct ctrl_node *cn );
+
+
+#endif
Added: trunk/bmx/avl.c
===================================================================
--- trunk/bmx/avl.c (rev 0)
+++ trunk/bmx/avl.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,684 @@
+/*
+ * 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.
+ *
+ * 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
+ */
+
+/*
+ * avl code inspired by:
+ *
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. ;-)
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#include "bmx.h"
+
+#include "avl.h"
+
+
+struct avl_node *avl_find( struct avl_tree *tree, void *key )
+{
+ struct avl_node *an = tree->root;
+ 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 ];
+
+ return an;
+}
+
+void *avl_find_item(struct avl_tree *tree, void *key)
+{
+ struct avl_node *an;
+
+ return ((an = avl_find(tree, key)) ? an->item : NULL);
+
+}
+
+struct avl_node *avl_next(struct avl_tree *tree, void *key)
+{
+ struct avl_node *an = tree->root;
+ struct avl_node *best = NULL;
+ int cmp;
+
+ while (an) {
+
+ cmp = (memcmp(AVL_NODE_KEY(tree, an), key, tree->key_size) <= 0);
+
+ if (an->link[cmp]) {
+ best = cmp ? best : an;
+ an = an->link[cmp];
+ } else {
+ return cmp ? best : an;
+ }
+
+ }
+ return NULL;
+}
+
+void * avl_next_item( struct avl_tree *tree, void *key)
+{
+ struct avl_node *an = avl_next(tree, key);
+
+ return an ? an->item : NULL;
+}
+
+
+struct avl_node *avl_iterate(struct avl_tree *tree, struct avl_node *an )
+{
+
+ if ( !an || an->link[1] ) {
+
+ an = an ? an->link[1] : tree->root;
+
+ while ( an && an->link[0] )
+ an = an->link[0];
+
+ return an;
+ }
+
+ struct avl_node *prev = an;
+
+ while ((an = an->up)) {
+
+ if ( an->link[0] == prev )
+ return an;
+
+ prev = an;
+ }
+
+ return NULL;
+}
+
+void *avl_iterate_item(struct avl_tree *tree, struct avl_node **an )
+{
+
+ if ( !(*an) || (*an)->link[1] ) {
+
+ (*an) = (*an) ? (*an)->link[1] : tree->root;
+
+ while ( (*an) && (*an)->link[0] )
+ (*an) = (*an)->link[0];
+
+ return (*an) ? (*an)->item : NULL;
+ }
+
+ struct avl_node *prev = (*an);
+
+ while (((*an) = (*an)->up)) {
+
+ if ( (*an)->link[0] == prev)
+ return (*an)->item;
+
+ prev = (*an);
+ }
+
+ return NULL;
+}
+
+
+
+static struct avl_node *avl_create_node(void *node, int32_t tag)
+{
+ struct avl_node *an = debugMalloc(sizeof (struct avl_node), tag);
+
+ memset( an, 0, sizeof( struct avl_node) );
+ an->item = node;
+
+ return an;
+}
+
+static struct avl_node *avl_rotate_single(struct avl_node *root, int dir)
+{
+ struct avl_node *save;
+ int rlh, rrh, slh;
+
+ /* Rotate */
+ save = root->link[!dir];
+
+ root->link[!dir] = save->link[dir];
+
+ if (root->link[!dir])
+ root->link[!dir]->up = root;
+
+ save->link[dir] = root;
+
+ if ( root )
+ root->up = save;
+
+ /* Update balance factors */
+ rlh = avl_height(root->link[0]);
+ rrh = avl_height(root->link[1]);
+ slh = avl_height(save->link[!dir]);
+
+ root->balance = avl_max(rlh, rrh) + 1;
+ save->balance = avl_max(slh, root->balance) + 1;
+
+ return save;
+}
+
+static struct avl_node *avl_rotate_double(struct avl_node *root, int dir)
+{
+ root->link[!dir] = avl_rotate_single(root->link[!dir], !dir);
+
+ if (root->link[!dir])
+ root->link[!dir]->up = root;
+
+ return avl_rotate_single(root, dir);
+}
+
+
+void avl_insert(struct avl_tree *tree, void *node, int32_t tag) {
+
+ if (tree->root) {
+
+ struct avl_node *it = tree->root;
+ struct avl_node *up[AVL_MAX_HEIGHT];
+ int upd[AVL_MAX_HEIGHT], top = 0;
+ int done = 0;
+
+ /* 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;
+ upd[top] = memcmp(AVL_NODE_KEY(tree, it), AVL_ITEM_KEY(tree,
node), tree->key_size) <= 0;
+
+ up[top++] = it;
+
+ if (it->link[upd[top - 1]] == NULL)
+ break;
+
+ it = it->link[upd[top - 1]];
+ }
+
+ /* 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 */
+ while (--top >= 0 && !done) {
+
+ int lh, rh, max;
+
+ lh = avl_height(up[top]->link[upd[top]]);
+ rh = avl_height(up[top]->link[!upd[top]]);
+
+ /* Terminate or rebalance as necessary */
+ if (lh - rh == 0)
+ done = 1;
+ if (lh - rh >= 2) {
+ struct avl_node *a =
up[top]->link[upd[top]]->link[upd[top]];
+ struct avl_node *b =
up[top]->link[upd[top]]->link[!upd[top]];
+
+ if (avl_height(a) >= avl_height(b))
+ up[top] = avl_rotate_single(up[top], !upd[top]);
+ else
+ up[top] = avl_rotate_double(up[top], !upd[top]);
+
+ /* Fix parent */
+ if (top != 0) {
+ up[top - 1]->link[upd[top - 1]] = up[top];
+ up[top]->up = up[top - 1];
+ } else {
+ tree->root = up[0];
+ up[0]->up = NULL;
+
+ }
+
+ done = 1;
+ }
+
+ /* Update balance factors */
+ lh = avl_height(up[top]->link[upd[top]]);
+ rh = avl_height(up[top]->link[!upd[top]]);
+ max = avl_max(lh, rh);
+
+ up[top]->balance = max + 1;
+ }
+
+ } else {
+
+ tree->root = avl_create_node(node, tag);
+ }
+
+ tree->items++;
+
+ return;
+}
+
+
+
+void *avl_remove(struct avl_tree *tree, void *key, int32_t tag)
+{
+ struct avl_node *it = tree->root;
+ struct avl_node *up[AVL_MAX_HEIGHT];
+ int upd[AVL_MAX_HEIGHT], top = 0, cmp;
+
+ 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))) {
+
+ // Push direction and node onto stack
+ upd[top] = (cmp < 0);
+ up[top] = it;
+ top++;
+
+ if (!(it = it->link[(cmp < 0)]))
+ return NULL;
+
+ }
+
+ // remember and return the found node. It might have been another one than
intended
+ void *node = it->item;
+
+ // Remove the node:
+ if (!(it->link[0] && it->link[1])) { // at least one child is
NULL:
+
+ // Which child is not null?
+ int dir = !(it->link[0]);
+
+ /* Fix parent */
+ if (top) {
+ up[top - 1]->link[upd[top - 1]] = it->link[dir];
+ if (it->link[dir])
+ it->link[dir]->up = up[top - 1];
+ } else {
+ tree->root = it->link[dir];
+ if (tree->root)
+ tree->root->up = NULL;
+ }
+ debugFree(it, tag);
+
+ } else { // both childs NOT NULL:
+
+ // Find the inorder successor
+ struct avl_node *heir = it->link[1];
+
+ // Save the path
+ upd[top] = 1;
+ up[top] = it;
+ top++;
+
+ while (heir->link[0]) {
+ upd[top] = 0;
+ up[top] = heir;
+ top++;
+ heir = heir->link[0];
+ }
+
+ // Swap data
+ it->item = heir->item;
+
+ // Unlink successor and fix parent
+ up[top - 1]->link[ (up[top - 1] == it) ] = heir->link[1];
+
+ if ( heir->link[1])
+ heir->link[1]->up = up[top - 1];
+
+ debugFree(heir, tag);
+ }
+
+ tree->items--;
+
+ // Walk back up the search path
+ while (--top >= 0) {
+ int lh = avl_height(up[top]->link[upd[top]]);
+ int rh = avl_height(up[top]->link[!upd[top]]);
+ int max = avl_max(lh, rh);
+
+ /* Update balance factors */
+ up[top]->balance = max + 1;
+
+
+ // Terminate or re-balance as necessary:
+ if (lh - rh >= 0) // re-balance upper path...
+ continue;
+
+ if (lh - rh == -1) // balance for upper path unchanged!
+ break;
+
+ if (!(up[top]) || !(up[top]->link[!upd[top]])) {
+ dbgf(DBGL_SYS, DBGT_ERR, "up(top) %p link %p lh %d rh
%d",
+ (void*)(up[top]), (void*)((up[top]) ?
(up[top]->link[!upd[top]]) : NULL), lh, rh);
+
+ paranoia(-500187, (!(up[top])));
+ paranoia(-500188, (!(up[top]->link[!upd[top]])));
+ }
+
+ // if (lh - rh <= -2): rebalance here and upper path
+
+ struct avl_node *a = up[top]->link[!upd[top]]->link[upd[top]];
+ struct avl_node *b = up[top]->link[!upd[top]]->link[!upd[top]];
+
+ if (avl_height(a) <= avl_height(b))
+ up[top] = avl_rotate_single(up[top], upd[top]);
+ else
+ up[top] = avl_rotate_double(up[top], upd[top]);
+
+ // Fix parent:
+ if (top) {
+ up[top - 1]->link[upd[top - 1]] = up[top];
+ up[top]->up = up[top - 1];
+ } else {
+ tree->root = up[0];
+ tree->root->up = NULL;
+ }
+ }
+
+ return node;
+
+}
+
+#ifdef AVL_DEBUG
+
+struct avl_node *_avl_iter_down(int dir, struct avl_node *an, struct avl_iterator *it )
{
+
+ for (; an; it->top++) {
+ /* Push direction and node onto stack */
+ it->up[it->top] = an;
+ it->upd[it->top] = dir;
+
+ an = an->link[dir];
+ }
+ it->top--;
+ return it->up[it->top];
+}
+
+struct avl_node *avl_iter(struct avl_tree *tree, struct avl_iterator *it ) {
+
+ struct avl_node *an = tree->root;
+ if ( !an )
+ return NULL;
+
+ if (!it->up[0]) {
+ // Get initial element and fill stack:
+ // go left...
+ it->top=0;
+ return _avl_iter_down( 0/*left*/, an, it );
+ }
+
+ if ((an = it->up[(it->top)]->link[1])) {
+ //go one right, then left...
+ it->upd[it->top] = 1;
+ it->top++;
+ return _avl_iter_down(0, an, it);
+ }
+
+ while (it->top > 0 && it->upd[(it->top) - 1] == 1 /*was: down
right*/) {
+ //so go one back up (up-left = opposite of down right)
+ it->top--;
+ }
+
+ if (it->top > 0 && it->upd[(it->top) - 1] == 0 /*was: down
left*/) {
+ //so go one back up (up-right = opposite of down left)):
+ it->top--;
+ return it->up[it->top];
+ }
+
+ it->up[0] = NULL;
+ return NULL;
+}
+
+void avl_debug( struct avl_tree *tree ) {
+
+ #define AVL_DBG_COL_CHARS 6
+
+ int i,j;
+
+ int depth_min = 0;
+
+ struct avl_node *an;
+ for (an = tree->root; an; an = an->link[0])
+ depth_min++;
+
+ int depth_max = depth_min+2;
+ int width = 1<<depth_max;
+
+ char * dbg_mem = malloc( depth_max * width * AVL_DBG_COL_CHARS + 1);
+ memset( dbg_mem, ' ', depth_max * width * AVL_DBG_COL_CHARS + 1 );
+
+ for( i=1; i<=depth_max; i++ )
+ dbg_mem[(i*width*AVL_DBG_COL_CHARS)-1] = '\n';
+
+ dbg_mem[ depth_max * width * AVL_DBG_COL_CHARS ] = 0;
+
+ struct avl_iterator it;
+ memset ( &it, 0, sizeof( struct avl_iterator ) );
+
+ while( (an = avl_iter( tree, &it )) ) {
+
+ j = (width - 1) * AVL_DBG_COL_CHARS / 2;
+
+ for (i = 0; i < it.top; i++) {
+
+ int k = ((width - 1) * AVL_DBG_COL_CHARS );
+ int l = 4<<i;
+ int m = ( it.upd[i]?1:-1);
+
+ j = j + (m * k / l);
+ }
+
+// dbg_mem[((i * width * AVL_DBG_COL_CHARS) + j)] = 'x';
+
+ snprintf(&dbg_mem[((i * width * AVL_DBG_COL_CHARS) + j)],
AVL_DBG_COL_CHARS,
+ "%3d/%1d", ((int*) AVL_NODE_KEY(tree, an))[0], ((int*)
AVL_NODE_KEY(tree, an))[1]);
+
+ dbg_mem[((i * width * AVL_DBG_COL_CHARS) + j + (AVL_DBG_COL_CHARS-1))] =
' ';
+
+
+ printf("%3d/%1d ", ((int*) AVL_NODE_KEY(tree, an))[0], ((int*)
AVL_NODE_KEY(tree, an))[1]);
+ }
+
+
+ dbg_mem[ depth_max * width * AVL_DBG_COL_CHARS ] = 0;
+
+ printf("\n-----\n%s\n-----\n", dbg_mem );
+
+}
+#endif
+
+#ifdef AVL_TEST
+
+void avl_test( int max ) {
+
+#define AVL_TEST_MAX max
+
+ struct test_type {
+ int32_t test_key;
+ int32_t v;
+ uint8_t k;
+ int32_t test_key2;
+ int32_t w;
+ };
+
+ struct avl_node *an = NULL;
+ AVL_TREE(test_tree, struct test_type, test_key );
+ AVL_TREE(test_tree2, struct test_type, test_key2 );
+
+ int32_t i, j;
+
+ struct test_type * t;
+
+
+
+ // insert something:
+
+ for (i = 0; i <= AVL_TEST_MAX; i++) {
+ t = debugMalloc(sizeof ( struct test_type), -300004);
+ 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);
+ printf(" inserted %d/%d %d/%d\n", t->test_key, t->v,
t->test_key2, t->w );
+ }
+
+/*
+ // remove something:
+
+ for (i = AVL_TEST_MAX/2; i >= 0; i--) {
+
+ t = avl_remove(&test_tree, &i);
+
+ if ( t != avl_remove(&test_tree2, &t->test_key2) )
+ printf("ERROR...\n");
+
+ printf(" removed %d/%d %d/%d\n", t->test_key, t->v,
t->test_key2, t->w );
+ debugFree( t, -300038 );
+ }
+*/
+
+
+
+
+ // debug test_tree:
+
+ printf("\navl_iterate( test_tree ):\n");
+ i=0;
+ an = NULL;
+ while( (an = avl_iterate( &test_tree, an ) ) ) {
+ t = ((struct test_type*)(an->item));
+ if ( i > t->test_key)
+ printf("\nERROR %d > %d \n", i, t->test_key);
+ i = t->test_key;
+ printf( "%3d/%1d ", t->test_key, t->v );
+ }
+
+ printf("\navl_next():\n");
+ i = 0; j = 0;
+ while( (an = avl_next( &test_tree, &j )) ) {
+ t = ((struct test_type*)(an->item));
+ j = t->test_key;
+ if ( i > t->test_key)
+ printf("\nERROR %d > %d \n", i, t->test_key);
+
+ i = t->test_key;
+
+ printf( "N%4d/%1d ", t->test_key, t->v );
+
+ if ( i%10 == 0 )
+ printf("\n");
+
+ }
+
+#ifdef AVL_DEBUG
+ printf("\navl_debug():\n");
+ avl_debug( &test_tree );
+#endif
+
+ printf("\n");
+
+
+
+
+ // debug test_tree2:
+
+ printf("\navl_iterate( test_tree2 ):\n");
+ i=0;
+ an = NULL;
+ while( (an = avl_iterate( &test_tree2, an ) ) ) {
+ t = ((struct test_type*)(an->item));
+ if ( i > t->test_key2)
+ printf("\nERROR %d > %d \n", i, t->test_key2);
+ i = t->test_key2;
+ printf( "%3d/%1d ", t->test_key2, t->w );
+ }
+
+ printf("\navl_next( test_tree2):\n");
+ i = 0; j = 0;
+ while( (an = avl_next( &test_tree2, &j )) ) {
+ t = ((struct test_type*)(an->item));
+ j = t->test_key2;
+ if ( i > t->test_key2)
+ printf("\nERROR %d > %d \n", i, t->test_key2);
+
+ i = t->test_key2;
+
+ printf( "N%4d/%1d ", t->test_key2, t->w );
+
+ if ( i%10 == 0 )
+ printf("\n");
+
+ }
+
+#ifdef AVL_DEBUG
+ printf("\navl_debug():\n");
+ avl_debug( &test_tree2 );
+#endif
+
+ printf("\n");
+
+
+ // remove whats left:
+
+ while( test_tree.root ) {
+ t = (struct test_type*)test_tree.root->item;
+ avl_remove(&test_tree, &t->test_key, -300190);
+ avl_remove(&test_tree2, &t->test_key2, -300191);
+ printf(" removed %d/%d %d/%d\n", t->test_key, t->v,
t->test_key2, t->w );
+ debugFree( t, -300042 );
+ }
+
+ printf("\n");
+ cleanup_all(CLEANUP_SUCCESS);
+}
+
+
+static int32_t tree_max = 5;
+static int32_t opt_tree ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct
opt_parent *patch, struct ctrl_node *cn ) {
+
+ if ( cmd == OPT_APPLY )
+ avl_test(tree_max);
+
+ return SUCCESS;
+}
+
+static 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, "\navl tree debuggin options:"}
+,
+ {ODI,0,"tree", 0,
5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &tree_max, 0, 20, 1,
opt_tree,
+ ARG_VALUE_FORM, "show tree with given number of elements"}
+
+};
+
+
+
+#endif
+
+void init_avl( void )
+{
+#ifdef AVL_TEST
+ register_options_array( msg_options, sizeof( msg_options ) );
+#endif
+}
Added: trunk/bmx/avl.h
===================================================================
--- trunk/bmx/avl.h (rev 0)
+++ trunk/bmx/avl.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * 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
+ */
+
+/*
+ * avl code inspired by:
+ *
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. ;-)
+ */
+
+#ifndef _AVL_H
+#define _AVL_H
+
+#include <stdint.h>
+
+
+#define AVL_MAX_HEIGHT 128
+
+
+struct avl_node {
+ void *item;
+ int balance;
+ struct avl_node * up;
+ struct avl_node * link[2];
+};
+
+// obtain key pointer based on avl_node pointer
+#define AVL_NODE_KEY( a_tree, a_node ) ( (void*) (
((char*)(a_node)->item)+((a_tree)->key_offset) ) )
+
+// obtain key pointer based on item pointer
+#define AVL_ITEM_KEY( a_tree, a_item ) ( (void*) (
((char*)(a_item))+((a_tree)->key_offset) ) )
+
+struct avl_tree {
+ struct avl_node *root;
+ uint16_t key_size;
+ uint16_t key_offset;
+ uint32_t items;
+};
+
+
+#define AVL_INIT_TREE(tree, element_type, key_field) do { \
+ tree.root = NULL; \
+ tree.key_size = sizeof( (((element_type *) 0)->key_field) );
\
+ tree.key_offset = ((unsigned long) (&((element_type *)
0)->key_field)); \
+ tree.items = 0; \
+ } while (0)
+
+#define AVL_TREE(tree, element_type, key_field) struct avl_tree (tree) = { \
+ NULL, \
+ (sizeof( (((element_type *) 0)->key_field) )), \
+ ((unsigned long)(&((element_type *)0)->key_field)), \
+ 0 }
+
+#define avl_height(p) ((p) == NULL ? -1 : (p)->balance)
+#define avl_max(a,b) ((a) > (b) ? (a) : (b))
+
+
+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);
+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 );
+
+void avl_insert(struct avl_tree *tree, void *node, int32_t tag);
+void *avl_remove(struct avl_tree *tree, void *key, int32_t tag);
+
+void init_avl(void);
+
+#ifdef AVL_DEBUG
+struct avl_iterator {
+ struct avl_node * up[AVL_MAX_HEIGHT];
+ int upd[AVL_MAX_HEIGHT];
+ int top;
+};
+
+struct avl_node *avl_iter(struct avl_tree *tree, struct avl_iterator *it );
+void avl_debug( struct avl_tree *tree );
+void avl_test(int m);
+#endif
+
+
+#endif
Added: trunk/bmx/bmx.c
===================================================================
--- trunk/bmx/bmx.c (rev 0)
+++ trunk/bmx/bmx.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,2279 @@
+/*
+ * 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.
+ *
+ * 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 <arpa/inet.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/if.h> /* ifr_if, ifr_tun */
+#include <linux/rtnetlink.h>
+#include <time.h>
+
+#include "bmx.h"
+#include "msg.h"
+#include "hna.h"
+#include "plugin.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;
+
+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;
+
+
+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;
+
+
+static int32_t purge_to = DEF_PURGE_TO;
+
+
+void* FAILURE_POINTER = &FAILURE_POINTER;
+
+static int8_t stop = 0;
+
+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;
+
+uint32_t bmx_time = 0;
+uint32_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;
+
+
+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(blacklisted_tree, struct black_node, dhash);
+
+AVL_TREE(link_dev_tree, struct link_dev_node, key);
+
+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 );
+
+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
+ ************************************************************/
+
+
+
+void blacklist_neighbor(struct packet_buff *pb)
+{
+
+ dbgf(DBGL_SYS, DBGT_ERR, "%s via %s", pb->neigh_str,
pb->iif->name);
+}
+
+
+IDM_T blacklisted_neighbor(struct packet_buff *pb, struct description_hash *dhash)
+{
+
+ dbgf(DBGL_ALL, DBGT_INFO, "%s via %s", pb->neigh_str,
pb->iif->name);
+ return NO;
+}
+
+
+IDM_T validate_metric_algo(struct metric_algo *ma, struct ctrl_node *cn)
+{
+
+ 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);
+
+ } else if (ma->sqn_lounge % ma->sqn_steps) {
+
+ dbg_cn(cn, DBGL_SYS, DBGT_ERR, "SQN: lounge=%d MUST BE multiple of
steps=%d",
+ ma->sqn_lounge, ma->sqn_steps);
+ } else {
+
+ return SUCCESS;
+ }
+
+ return FAILURE;
+}
+
+
+uint32_t update_metric(struct metric_record *mr, struct metric_algo *ma, SQN_T sqn_in,
SQN_T sqn_max, uint32_t probe)
+{
+
+ dbgf(DBGL_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,
+ "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;
+ }
+
+
+ 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;
+
+
+ } 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;
+}
+
+
+
+
+
+STATIC_FUNC
+void assign_best_rtq_link(struct neigh_node *nn)
+{
+ struct list_node *lndev_pos;
+ struct link_dev_node *lndev_best = NULL;
+ struct link_node *ln;
+ struct avl_node *an = NULL;
+
+ assertion( -500451, (nn));
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s", nn->dhn->on->id.name);
+
+ while ((ln = avl_iterate_item(&nn->link_tree, &an))) {
+
+ list_for_each(lndev_pos, &ln->lndev_list)
+ {
+ 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_best = lndev;
+
+ }
+
+ }
+ assertion( -500406, (lndev_best));
+
+ nn->best_rtq = lndev_best;
+
+}
+
+
+
+//BMX3 (done)
+STATIC_FUNC
+void free_neigh_node(struct neigh_node *nn)
+{
+ paranoia(-500321, (nn->link_tree.items));
+
+ dbgf(DBGL_SYS, DBGT_INFO," ");
+
+ avl_remove(&neigh_tree, &nn->nnkey, -300196);
+ iid_purge_repos(&nn->neighIID4x_repos);
+ debugFree(nn, -300129);
+}
+
+
+/*
+ * 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)
+{
+ 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_insert(&nn->link_tree, ln, -300172);
+
+ nn->dhn = dhn;
+
+ nn->nnkey = nn;
+ avl_insert(&neigh_tree, nn, -300141);
+
+ dhn->neigh = ln->neigh = nn;
+
+ return nn;
+}
+
+
+//BMX3 (done)
+IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T
neighIID4neigh)
+{
+ struct neigh_node *neigh = NULL;
+
+ dbgf( DBGL_SYS, DBGT_INFO, "neigh %s neighIID4neigh %d dhn->orig
%s",
+ ln->llip4_str, neighIID4neigh, dhn->on->desc0->id.name);
+
+ assertion(-500389, (ln && neighIID4neigh > IID_RSVD_MAX));
+ assertion(-500390, (dhn && dhn->on));
+
+ if (ln->neigh) {
+
+ 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)));
+
+ 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;
+
+
+ } else {
+
+ neigh = merge_neigh_nodes( ln, dhn);
+
+ }
+
+ } else {
+
+ if ( dhn->neigh ) {
+
+ assertion(-500394, (dhn->neigh->dhn == dhn));
+ assertion(-500395, (dhn->neigh->link_tree.items));
+ ASSERTION(-500396, (!avl_find(&dhn->neigh->link_tree,
&ln->llip4)));
+
+ neigh = ln->neigh = dhn->neigh;
+ avl_insert(&neigh->link_tree, ln, -300173);
+
+ } else {
+
+ neigh = create_neigh_node( ln, dhn );
+
+ }
+
+ }
+
+ assign_best_rtq_link(neigh);
+
+ return update_neighIID4x_repository(neigh, neighIID4neigh, neigh->dhn);
+}
+
+
+STATIC_FUNC
+struct link_dev_node *get_link_dev_node(struct link_node *ln, struct dev_node *dev)
+{
+ struct list_node *lndev_pos;
+ struct link_dev_node *lndev;
+
+ list_for_each( lndev_pos, &ln->lndev_list ) {
+
+ lndev = list_entry( lndev_pos, struct link_dev_node, list );
+
+ if ( lndev->key.dev == dev )
+ 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;
+
+ dbgf( DBGL_CHANGES, DBGT_INFO, "creating new lndev %16s %10s %s",
+ ipStr(ln->llip4), dev->name, dev->ip4_str );
+
+ list_add_tail(&ln->lndev_list, &lndev->list);
+
+ ASSERTION( -500489, !avl_find( &link_dev_tree, &lndev->key));
+
+ avl_insert( &link_dev_tree, lndev, -300220 );
+
+ lndev->link = ln;
+
+ 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(&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(&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(DBGL_CHANGES, 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(DBGL_CHANGES, 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_SYS, 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);
+
+ dbgf(DBGL_SYS, DBGT_INFO, "ln->neigh %s (%d more
link_tree.items)",
+ ln->llip4_str, nn->link_tree.items);
+
+ if (!nn->link_tree.items) {
+
+ if (nn->dhn) {
+ dbgf(DBGL_SYS, DBGT_INFO, "setting
ln->neigh->dhn (%s) = NULL",
+ nn->dhn->on->id.name);
+ 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)
+{
+
+ struct dhash_node * dhn = debugMalloc(sizeof ( struct dhash_node), -300001);
+ memset(dhn, 0, sizeof ( struct dhash_node));
+ memcpy(&dhn->dhash, dhash, BMX_HASH0_LEN);
+ avl_insert(&dhash_tree, dhn, -300142);
+
+ dhn->myIID4orig = iid_new_myIID4x(dhn);
+
+ on->updated_timestamp = bmx_time;
+ dhn->on = on;
+ on->dhn = dhn;
+
+ 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)
+{
+ 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 ) {
+
+ struct dhash_node *dhn;
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s", purge_all ? "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)) {
+
+ dbgf(DBGL_CHANGES, 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);
+
+ } else {
+ break;
+ }
+ }
+}
+
+STATIC_FUNC
+void unlink_dhash_node(struct dhash_node *dhn)
+{
+ dbgf(DBGL_CHANGES, DBGT_INFO, "dhash %8X myIID4orig %d",
dhn->dhash.h.u32[0], dhn->myIID4orig);
+
+ if (dhn->neigh) {
+
+ struct avl_node *an;
+ struct link_node *ln;
+
+ while ((an = dhn->neigh->link_tree.root) && (ln =
an->item)) {
+
+ dbgf(DBGL_SYS, DBGT_INFO, "dhn->neigh->link_tree item
%s", ln->llip4_str);
+
+ assertion(-500284, (ln->neigh == dhn->neigh));
+
+ ln->neigh = NULL;
+
+ avl_remove(&dhn->neigh->link_tree, &ln->llip4,
-300197);
+ }
+
+ free_neigh_node(dhn->neigh);
+
+ dhn->neigh = NULL;
+ }
+
+ if (dhn->on) {
+ dhn->on->dhn = NULL;
+ free_orig_node( dhn->on );
+ 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);
+
+ invalidate_dhash_node(dhn);
+ return;
+
+ unlink_dhash_node(dhn);
+
+ free_dhash_iid(dhn);
+
+}
+
+void invalidate_dhash_node( struct dhash_node *dhn )
+{
+
+ dbgf(DBGL_CHANGES, 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
+
+ avl_insert(&dhash_invalid_tree, dhn, -300168);
+ plist_add_tail(&dhash_invalid_plist, dhn);
+ dhn->referred_timestamp = bmx_time;
+
+
+ //dhn->invalid=YES;
+}
+
+
+
+
+
+
+//BMX3 (done)
+IDM_T update_neighIID4x_repository(struct neigh_node *neigh, IID_T neighIID4x, struct
dhash_node *dhn)
+{
+ assertion(-500386, (neigh->dhn != my_orig_node.dhn));
+
+ if (dhn == my_orig_node.dhn)
+ neigh->neighIID4me = neighIID4x;
+
+ if (dhn == neigh->dhn)
+ neigh->neighIID4neigh = neighIID4x;
+
+ return iid_set_neighIID4x(&neigh->neighIID4x_repos, neighIID4x,
dhn->myIID4orig);
+}
+
+
+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));
+
+ while ((an = avl_next(&on->router_tree, &key))) {
+
+ struct router_node *rn = an->item;
+
+ memcpy(&key, &rn->key, sizeof (struct link_key));
+
+ if (purge_all || !avl_find(&link_dev_tree, &rn->key)) {
+ debugFree(rn, -300225);
+ avl_remove(&on->router_tree, &rn->key, -300226);
+ }
+ }
+}
+
+IDM_T update_orig_metrics(struct packet_buff *pb, struct orig_node *on, IID_T orig_sqn)
+{
+ dbgf(DBGL_ALL, DBGT_INFO, "%s orig_sqn %d via neigh %s",
on->id.name, orig_sqn,pb->neigh_str);
+
+ struct router_node *rn_in = NULL;
+ uint32_t metric_in, metric_best = 0;
+ SQN_T mask = on->path_metric_algo.sqn_mask;
+// SQN_T range = on->ogm_sqn_range;
+
+// return SUCCESS;
+
+ if (on->blocked || (((SQN_T) (orig_sqn - on->ogm_sqn_min)) >=
on->ogm_sqn_range))
+ return FAILURE;
+
+/*
+
+ if (((SQN_T) (((orig_sqn & mask) - (on->ogm_sqn_max_rcvd & mask)) -
1)) < on->ogm_sqn_range) {
+
+
+ for (;;) {
+ struct router_node *rn;
+ struct avl_node *an;
+// SQN_T min_sqn_level = ((orig_sqn & mask) -
on->ogm_sqn_steps);
+ struct router_node *rn_best = NULL;
+ uint32_t metric_temp;
+ metric_best = 0;
+
+ for (an = NULL; (rn = avl_iterate_item(&on->router_tree,
&an));) {
+
+ if (memcmp(&rn->key, &pb->lndev->key,
sizeof (struct link_key))) {
+
+ metric_temp = update_metric(&rn->mr,
&on->path_metric_algo, 0, orig_sqn, 0);
+
+ if (metric_best < metric_temp) {
+
+ metric_best = metric_temp;
+ rn_best = rn;
+ }
+
+ } else {
+ rn_in = rn;
+ }
+ }
+
+ if (rn_best && !avl_find(&link_dev_tree,
&rn_best->key)) {
+ purge_router_tree(on, NO);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ } else {
+ rn_in = avl_find_item(&on->router_tree,
&pb->lndev->key);
+ }
+
+ on->ogm_sqn_max_rcvd = MAX_SQ(on->ogm_sqn_max_rcvd, orig_sqn);
+
+ */
+ on->ogm_sqn_max_rcvd = MAX_SQ(on->ogm_sqn_max_rcvd, orig_sqn);
+
+ if (((SQN_T) ((on->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);
+
+ return FAILURE;
+ }
+
+ for (;;) {
+ struct router_node *rn;
+ struct avl_node *an;
+ struct router_node *rn_best = NULL;
+ uint32_t metric_temp;
+ metric_best = 0;
+
+ for (an = NULL; (rn = avl_iterate_item(&on->router_tree,
&an));) {
+
+ if (memcmp(&rn->key, &pb->lndev->key, sizeof
(struct link_key))) {
+
+ metric_temp = update_metric(&rn->mr,
&on->path_metric_algo, 0, on->ogm_sqn_max_rcvd, 0);
+
+ if (metric_best < metric_temp) {
+
+ metric_best = metric_temp;
+ rn_best = rn;
+ }
+
+ } else {
+ rn_in = rn;
+ }
+ }
+
+ if (rn_best && !avl_find(&link_dev_tree,
&rn_best->key)) {
+ purge_router_tree(on, NO);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+
+ 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->ogm_sqn_to_be_send = ((on->ogm_sqn_max_rcvd & mask) -
on->ogm_sqn_steps);
+ avl_insert(&on->router_tree, rn_in, -300223);
+ }
+
+ metric_in = update_metric(&rn_in->mr, &on->path_metric_algo,
orig_sqn, on->ogm_sqn_max_rcvd, pb->lndev->mr[SQR_RTQ].val);
+
+
+ if (metric_in > metric_best && GREAT_SQN(rn_in->mr.set & mask,
on->ogm_sqn_to_be_send & mask)) {
+
+ on->router_path_metric = metric_in;
+ on->ogm_sqn_to_be_send = rn_in->mr.set;
+ ogm_aggreg_pending++;
+
+ if (memcmp(&on->router_key, &rn_in->key, sizeof (struct
link_key))) {
+
+ struct link_dev_node *lndev_old =
avl_find_item(&link_dev_tree, &on->router_key);
+
+ 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 : "---");
+
+ assertion(-500504, (!on->router_key.llip4 || lndev_old));
+
+ if (on->router_key.llip4) {
+ configure_route(on->primary_ip4, 32, 0,
on->router_key.llip4, 0,
+ on->router_key.dev->index,
on->router_key.dev->name,
+ RT_TABLE_HOSTS, RTN_UNICAST, DEL,
TRACK_OTHER_HOST);
+ }
+
+ 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);
+
+ memcpy(&on->router_key, &rn_in->key, sizeof (struct
link_key));
+ }
+ }
+ return SUCCESS;
+}
+
+
+
+void free_orig_node(struct orig_node *on)
+{
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s", on->primary_ip4_str);
+
+ if ( on == &my_orig_node)
+ return;
+
+ if (on->router_key.llip4) {
+ configure_route(on->primary_ip4, 32, 0, on->router_key.llip4, 0,
+ on->router_key.dev->index, on->router_key.dev->name,
+ RT_TABLE_HOSTS, RTN_UNICAST, DEL, TRACK_OTHER_HOST);
+ }
+
+
+ process_description_tlvs(on, NULL, TLV_DEL_TEST_ADD, 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 );
+ debugFree( on, -300086 );
+}
+
+
+
+
+void purge_orig(struct dev_node *only_dev, IDM_T only_expired)
+{
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s %s only expired",
+ only_dev ? only_dev->name : "---", only_expired ? "
" : "NOT");
+
+ purge_link_node( 0, only_dev, only_expired );
+
+ int i;
+ for (i = IID_RSVD_MAX + 1; i < my_iid_repos.max_free; i++) {
+
+ struct dhash_node *dhn;
+
+ 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);
+
+ } else if (!only_expired || ((uint32_t) (bmx_time -
dhn->referred_timestamp)) > (uint32_t) purge_to) {
+
+ free_orig_node(dhn->on);
+ }
+ }
+ }
+}
+
+struct dev_node * get_bif(char *dev)
+{
+ char dev_name[IFNAMSIZ];
+ memset(dev_name, 0, IFNAMSIZ);
+
+ strncpy(dev_name, dev, IFNAMSIZ - 1);
+
+ return avl_find_item(&dev_name_tree, dev_name);
+
+}
+
+
+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;
+ }
+
+ if ((dev = avl_find_item(&dev_ip4_tree, &pb->pkt_buff_llip4))) {
+ // mark own packets;
+ pb->oif = iif;
+ } else {
+ pb->oif = NULL;
+ }
+
+
+ addr_to_str( pb->pkt_buff_llip4, pb->neigh_str );
+
+ // 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) {
+
+ goto process_packet_error_hdr;
+ }
+
+ 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 (!pb->oif) {
+
+ iif->link_activity_timestamp = bmx_time;
+
+ } else if (((SQN_T) (pb->oif->packet_sqn - hdr->pkt_dev_sqn)) > 2) {
+
+ 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);
+
+ goto process_packet_error_hdr;
+
+ } else {
+ 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) {
+
+ 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);
+
+ 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(DBGL_ALL, DBGT_INFO, "rcvd packet from %s size %d via dev %s",
+ pb->neigh_str, hdr->pkt_length, iif->name);
+
+ if (blacklisted_neighbor(pb, NULL))
+ return;
+
+ if (rx_frames(pb, hdr->pkt_data, hdr->pkt_length - sizeof (struct
packet_header)) == SUCCESS)
+ return;
+
+process_packet_error_hdr:
+ 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);
+
+ return;
+}
+
+
+/***********************************************************
+ Runtime Infrastructure
+************************************************************/
+
+void upd_time( struct timeval *precise_tv ) {
+
+ timeradd( &max_tv, &new_tv, &acceptable_p_tv );
+ timercpy( &acceptable_m_tv, &new_tv );
+ gettimeofday( &new_tv, NULL );
+
+ if ( timercmp( &new_tv, &acceptable_p_tv, > ) ) {
+
+ timersub( &new_tv, &acceptable_p_tv, &diff_tv );
+ timeradd( &start_time_tv, &diff_tv, &start_time_tv );
+
+ dbg( DBGL_SYS, DBGT_WARN,
+ "critical system time drift detected: ++ca %ld s, %ld us! Correcting
reference!",
+ diff_tv.tv_sec, diff_tv.tv_usec );
+
+ if ( diff_tv.tv_sec > CRITICAL_PURGE_TIME_DRIFT )
+ purge_orig(NULL, NO);
+
+ } else if ( timercmp( &new_tv, &acceptable_m_tv, < ) ) {
+
+ timersub( &acceptable_m_tv, &new_tv, &diff_tv );
+ timersub( &start_time_tv, &diff_tv, &start_time_tv );
+
+ dbg( DBGL_SYS, DBGT_WARN,
+ "critical system time drift detected: --ca %ld s, %ld us! Correcting
reference!",
+ diff_tv.tv_sec, diff_tv.tv_usec );
+
+ if ( diff_tv.tv_sec > CRITICAL_PURGE_TIME_DRIFT )
+ purge_orig(NULL, NO);
+
+ }
+
+ timersub( &new_tv, &start_time_tv, &ret_tv );
+
+ if ( precise_tv ) {
+ precise_tv->tv_sec = ret_tv.tv_sec;
+ precise_tv->tv_usec = ret_tv.tv_usec;
+ }
+
+ bmx_time = ( (ret_tv.tv_sec * 1000) + (ret_tv.tv_usec / 1000) );
+ bmx_time_sec = ret_tv.tv_sec;
+
+}
+
+
+
+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",
+ (((bmx_time_sec-reference)/86400)),
+ (((bmx_time_sec-reference)%86400)/36000)%10,
+ (((bmx_time_sec-reference)%86400)/3600)%10,
+ (((bmx_time_sec-reference)%3600)/600)%10,
+ (((bmx_time_sec-reference)%3600)/60)%10,
+ (((bmx_time_sec-reference)%60)/10)%10,
+ (((bmx_time_sec-reference)%60))%10
+ );
+
+ return ut;
+}
+
+
+void wait_sec_msec( uint32_t sec, uint32_t msec ) {
+
+ 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;
+}
+
+
+
+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 ) {
+
+ 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);
+
+
+}
+
+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);
+
+ if (!segfault) {
+
+ segfault = YES;
+
+ signal(SIGSEGV, SIG_DFL);
+
+
+ if (!on_the_fly)
+ 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 ...");
+ }
+
+ errno=0;
+ if ( raise( SIGSEGV ) ) {
+ dbg( DBGL_SYS, DBGT_ERR, "raising SIGSEGV failed: %s...", strerror(errno) );
+ }
+}
+
+
+void cleanup_all(int status)
+{
+
+ if (status < 0) {
+ dbg(DBGL_SYS, DBGT_ERR, "Terminating with error code %d ! Please
notify a developer", status);
+ segmentation_fault(1);
+ }
+
+ if (!cleaning_up) {
+
+ dbgf_all(DBGT_INFO, "cleaning up (status %d)...", status);
+
+ cleaning_up = YES;
+
+ // first, restore defaults...
+
+ stop = 1;
+
+ cleanup_schedule();
+
+
+ if (my_orig_node.dhn) {
+ my_orig_node.dhn->on = NULL;
+ free_dhash_node(my_orig_node.dhn);
+ }
+
+ avl_remove(&orig_tree, &(my_orig_node.id), -300203);
+
+ purge_orig( NULL, NO );
+
+ cleanup_plugin();
+
+ cleanup_config();
+
+ cleanup_route();
+
+ cleanup_msg();
+
+ purge_dhash_to_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();
+
+ dbgf_all( DBGT_ERR, "...cleaning up done");
+
+ if (status == CLEANUP_SUCCESS) {
+
+ exit(EXIT_SUCCESS);
+
+ } else if (status == CLEANUP_FAILURE) {
+
+ exit(EXIT_FAILURE);
+
+ } else if (status == CLEANUP_RETURN) {
+
+ return;
+
+ }
+
+ exit(EXIT_FAILURE);
+ dbg(DBGL_SYS, DBGT_ERR, "exit ignored!?");
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+/***********************************************************
+ Configuration data and handlers
+************************************************************/
+
+
+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)
+{
+
+ int rq, tq, rtq;
+
+ 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");
+
+ 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,
+ get_human_uptime(0), s_curr_avg_cpu_load / 10,
s_curr_avg_cpu_load % 10);
+
+
+ } else if ( !strcmp( opt->long_name, ARG_LINKS ) ) {
+
+ dbg_printf(cn, "LinkLocalIP viaIF bestIF
primaryIP RTQ RQ TQ oid4m lseq lvld\n");
+
+ struct avl_node *it = NULL;
+
+ while ((it = avl_iterate(&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,
+ nn ? nn->neighIID4me : 0,
+ ln->rq_sqn_max,
+ (bmx_time - lndev->rtq_time_max) /
1000
+ );
+
+ }
+
+ }
+
+ } 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 ) {
+
+ 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 );
+
+ for (i = 0; i < FRAME_TYPE_ARRSZ; i++) {
+ LIST_INIT_HEAD(dev->tx_tasks_list[i], struct
tx_task_node, list);
+ }
+
+ 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;
+ }
+
+ dev->soft_conf_changed = YES;
+
+ }
+
+
+ } 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)
+{
+
+ 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;
+
+ 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)
+{
+
+ 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)
+{
+
+
+ if (cmd == OPT_CHECK || cmd == OPT_APPLY || cmd == OPT_REGISTER) {
+
+ struct metric_algo test_algo;
+ memset(&test_algo, 0, sizeof (struct metric_algo));
+
+ 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[]=
+{
+// 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, "\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,
+ 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,
+ 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,
+ 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,
+ 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_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"}
+,
+
+ {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 ) {
+
+ int i,len;
+ if ( (len = strlen( name )) >= DESCRIPTION0_ID_NAME_LEN )
+ return FAILURE;
+
+ for (i = 0; i < len; i++) {
+
+ char c = name[i];
+
+ if (c == '"' || c < ' ' || c > '~')
+ return FAILURE;
+
+ }
+
+ return SUCCESS;
+}
+
+STATIC_FUNC
+void init_bmx(void)
+{
+
+ static uint8_t my_desc0[MAX_PKT_MSG_SIZE];
+
+ memset( &my_orig_node, 0, sizeof(struct orig_node));
+
+ AVL_INIT_TREE((my_orig_node.router_tree), struct router_node, key);
+
+ my_orig_node.desc0 = (struct description *) my_desc0;
+
+ if (gethostname(my_orig_node.id.name, DESCRIPTION0_ID_NAME_LEN))
+ cleanup_all(-500240);
+
+ my_orig_node.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);
+ 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);
+
+ my_orig_node.ogm_sqn_min = (((uint16_t) rand_num(MAX_SQN)) & (MAX_SQN
<< MAX_OGM0_PQ_BITS));
+
+ my_orig_node.desc0_sqn = rand_num(MAX_SQN);
+
+ avl_insert( &orig_tree, &my_orig_node, -300175 );
+
+ register_options_array( bmx_options, sizeof( bmx_options ) );
+
+}
+
+
+
+
+STATIC_FUNC
+void bmx(void)
+{
+
+ struct list_node *list_pos;
+ struct dev_node *dev;
+ uint32_t regular_timeout, statistic_timeout;
+
+ uint32_t s_last_cpu_time = 0, s_curr_cpu_time = 0;
+
+ regular_timeout = statistic_timeout = bmx_time;
+
+ on_the_fly = YES;
+
+ while ( !terminating() ) {
+
+ uint32_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 );
+
+ // 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 );
+
+ purge_tx_timestamp_tree(dev, NO);
+
+ }
+
+ purge_orig(NULL, YES);
+
+ purge_dhash_to_list(NO);
+
+ close_ctrl_node( CTRL_CLEANUP, 0 );
+
+ list_for_each( list_pos, &dbgl_clients[DBGL_ALL] ) {
+
+ struct ctrl_node *cn = (list_entry( list_pos, struct dbgl_node, list ))->cn;
+
+ dbg_printf( cn, "------------------ DEBUG ------------------ \n" );
+
+ 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_LINKS ), 0, cn
);
+ check_apply_parent_option( ADD, OPT_APPLY, 0, get_option(
0, 0, ARG_ORIGINATORS ), 0, cn );
+ dbg_printf( cn, "--------------- END DEBUG ---------------\n" );
+
+ }
+
+ /* preparing the next debug_timeout */
+ regular_timeout = bmx_time;
+ }
+
+
+ if ( LESS_U32( 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(DBGL_CHANGES, DBGT_INFO, "trying to unblock
%s...", on->desc0->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));
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "...unblocking %s %s
!",
+ on->desc0->id.name, tlvs_res ==
TLVS_SUCCESS ? "success" : "failed");
+
+ }
+
+
+ // check for corrupted memory..
+ checkIntegrity();
+
+
+ /* generating cpu load statistics... */
+ s_curr_cpu_time = (uint32_t)clock();
+
+ s_curr_avg_cpu_load = ( (s_curr_cpu_time - s_last_cpu_time) / (uint32_t)(bmx_time -
statistic_timeout) );
+
+ s_last_cpu_time = s_curr_cpu_time;
+
+ statistic_timeout = bmx_time;
+ }
+ }
+
+}
+
+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 );
+
+ upd_time( NULL );
+
+ My_pid = getpid();
+
+ srand( My_pid );
+
+ init_set_bits_table256();
+
+
+ signal( SIGINT, handler );
+ signal( SIGTERM, handler );
+ signal( SIGPIPE, SIG_IGN );
+ signal( SIGSEGV, segmentation_fault );
+
+ init_control();
+
+ init_route();
+
+ init_bmx();
+
+ init_msg();
+
+ init_schedule();
+
+ init_avl();
+
+ init_plugin();
+
+ apply_init_args( argc, argv );
+
+ check_kernel_config( NULL );
+
+ bmx();
+
+ cleanup_all( CLEANUP_SUCCESS );
+
+ return -1;
+}
+
+
+
Added: trunk/bmx/bmx.h
===================================================================
--- trunk/bmx/bmx.h (rev 0)
+++ trunk/bmx/bmx.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,932 @@
+/*
+ * 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.
+ *
+ * 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 <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+
+#include "cyassl/sha.h"
+
+#include "avl.h"
+#include "list.h"
+#include "iid.h"
+#include "control.h"
+#include "allocate.h"
+
+
+/*
+ * from other headers:
+ */
+
+#define IDM_T int8_t // int which size does NOT matter
+
+// dont touch this for compatibility reasons:
+#define IP4_T uint32_t
+
+#define DESCRIPTION0_ID_RANDOM_T uint64_t
+#define DESCRIPTION0_ID_RANDOM_LEN sizeof( DESCRIPTION0_ID_RANDOM_T )
+#define DESCRIPTION0_ID_NAME_LEN 22
+
+#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;
+} __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:
+ */
+
+
+#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"
+
+#define SQN_DAD_RANGE 64 // if rcvd sqn is >= last_rcvd_sqn + SQN_TIMEOUT_RANGE then
DAD
+#define SQN_T uint16_t
+
+#define MIN_SQN 0
+#define MAX_SQN ((SQN_T)-1)
+#define DEF_SQN 0 /* causes seqno to be randomized */
+
+
+#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"
+
+
+
+
+
+
+#define MIN_MASK 1
+#define MAX_MASK 32
+#define ARG_MASK "netmask"
+#define ARG_NETW "network"
+
+
+#define ARG_DEBUG "debug"
+#define ARG_NO_FORK "no_fork"
+#define ARG_QUIT "quit"
+
+#define ARG_CONNECT "connect"
+#define ARG_RUN_DIR "runtime_dir"
+#define DEF_RUN_DIR "/var/run/bmx"
+
+
+extern uint32_t My_pid;
+#define BMX_ENV_LIB_PATH "BMX_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"
+
+
+
+
+#define ARG_HELP "help"
+#define ARG_VERBOSE_HELP "verbose_help"
+#define ARG_EXP "exp_help"
+#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 VAL_DEV_LL_LO 0
+#define VAL_DEV_LL_LAN 1
+#define VAL_DEV_LL_WLAN 2
+
+
+#define ARG_ORIGINATORS "originators"
+#define ARG_STATUS "status"
+#define ARG_LINKS "links"
+#define ARG_ROUTES "routes"
+#define ARG_INTERFACES "interfaces"
+
+#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
+
+
+// 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 RQ_LINK_LOUNGE 0 /* may also be rtq_link_lounge */
+
+
+#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 DEF_DAD_TO 50000
+#define MIN_DAD_TO 100
+#define MAX_DAD_TO 360000000
+#define ARG_DAD_TO "dad_timeout"
+extern int32_t dad_to;
+
+#define MIN_ASOCIAL NO
+#define MAX_ASOCIAL YES
+#define DEF_ASOCIAL NO
+
+#define DEF_TTL 50 /* Time To Live of OGM broadcast messages */
+#define MAX_TTL 63
+#define MIN_TTL 1
+#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 MIN_DHASH_TO 300000
+#define DHASH_TO_TOLERANCE_FK 10
+
+
+
+
+
+#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
+
+enum NoYes {
+ NO,
+ YES
+};
+
+enum ADGSN {
+ ADD,
+ DEL,
+ GET,
+ SET,
+ NOP
+};
+
+
+#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 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 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_SQ( a, b ) ( (GREAT_SQN( (a), (b) )) ? (a) : (b) )
+
+
+
+
+#define WARNING_PERIOD 20000
+
+#define MAX_PATH_SIZE 300
+#define MAX_ARG_SIZE 200
+
+
+extern uint32_t bmx_time;
+extern uint32_t bmx_time_sec;
+
+extern uint8_t on_the_fly;
+
+
+extern uint32_t s_curr_avg_cpu_load;
+
+
+
+
+
+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 avl_tree link_tree;
+extern struct avl_tree link_dev_tree;
+
+extern struct avl_tree neigh_tree;
+
+extern struct avl_tree dhash_tree;
+extern struct avl_tree dhash_invalid_tree;
+
+extern struct avl_tree orig_tree;
+extern struct avl_tree blocked_tree;
+extern struct avl_tree blacklisted_tree;
+
+
+
+
+
+/**
+ * The most important data structures
+ */
+
+
+struct ogm_aggreg_node {
+
+ struct list_node list;
+
+ struct msg_ogm_adv *ogm_advs;
+
+ uint16_t aggregated_ogms;
+
+ SQN_T sqn;
+ uint8_t tx_attempts;
+ uint32_t tx_timestamp;
+};
+
+
+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;
+
+ //filled in by rx_frm_hey0_reps() or rx_frame()
+ struct link_dev_node *lndev;
+
+};
+
+
+
+
+struct task_node
+{
+ struct list_node list;
+ uint32_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 dev_node *dev; // the outgoing interface to be used for transmitting
+
+};
+
+struct tx_timestamp_key {
+ IP4_T myIID4x_or_dest_ip4;
+ IID_T neighIID4x;
+ uint16_t type;
+};
+
+struct tx_timestamp_node {
+ struct tx_timestamp_key key;
+ uint32_t timestamp;
+};
+
+struct dev_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 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 dev_node *dev;
+};
+
+struct link_dev_node {
+ struct list_node list;
+
+ struct link_key key;
+
+ uint32_t pkt_time_max;
+
+ uint32_t rtq_time_max;
+
+ struct link_node *link;
+
+// struct sq_record sqr[SQR_RANGE];
+
+ struct metric_record mr[SQR_RANGE];
+
+};
+
+/* 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;
+
+ 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 metric_record mr;
+
+// uint32_t metric;
+
+
+
+};
+
+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;
+
+ SQN_T ogm_sqn_min;
+ SQN_T ogm_sqn_to_be_send;
+ SQN_T ogm_sqn_aggregated;
+
+ SQN_T ogm_sqn_range;
+
+// SQN_T ogm_sqn_mask;
+// SQN_T ogm_sqn_steps;
+
+ 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;
+
+
+/*
+ // old unused:
+
+
+
+
+ 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
+
+ uint32_t first_valid_sec; // only used for debugging purposes
+
+ 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
+
+ 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 */
+ void *plugin_data[];
+
+};
+
+
+struct neigh_node {
+
+ struct neigh_node *nnkey;
+
+ struct avl_tree link_tree;
+
+ struct dhash_node *dhn;
+
+
+ // filled in by ???:
+
+ IID_T neighIID4me;
+ IID_T neighIID4neigh;
+
+ struct iid_repos neighIID4x_repos;
+
+ // filled in by ???:
+ 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];
+
+};
+
+
+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
+
+ 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
+};
+
+
+struct black_node {
+
+ struct description_hash dhash;
+};
+
+
+
+
+/* list element to store all the disabled tunnel rule netmasks */
+struct throw_node
+{
+ struct list_node list;
+ uint32_t addr;
+ uint8_t netmask;
+};
+
+
+
+
+# define timercpy(d, a) (d)->tv_sec = (a)->tv_sec; (d)->tv_usec =
(a)->tv_usec;
+
+
+
+enum {
+ CLEANUP_SUCCESS,
+ CLEANUP_FAILURE,
+ CLEANUP_MY_SIGSEV,
+ CLEANUP_RETURN
+};
+
+/*
+ * PARANOIA ERROR CODES:
+ * Negative numbers are used as SIGSEV error codes !
+ * Currently used numbers are: -500000 ... -500501
+ */
+
+#ifdef NO_PARANOIA
+#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)
+#ifdef EXTREME_PARANOIA
+#define ASSERTION( code , condition ); do { if ( !(condition) ) { cleanup_all( code ); }
}while(0)
+#define CHECK_INTEGRITY( ... ) checkIntegrity()
+#else
+#define CHECK_INTEGRITY( ... )
+#define ASSERTION( ... )
+#endif
+#endif
+
+
+#ifndef PROFILING
+#define STATIC_FUNC static
+#else
+#define STATIC_FUNC
+#endif
+
+#ifdef STATIC_VARIABLES
+#define STATIC_VAR static
+#else
+#define STATIC_VAR
+#endif
+
+/***********************************************************
+ Data Infrastructure
+ ************************************************************/
+
+void blacklist_neighbor(struct packet_buff *pb);
+
+IDM_T blacklisted_neighbor(struct packet_buff *pb, struct description_hash *dhash);
+
+IDM_T validate_metric_algo(struct metric_algo *ma, struct ctrl_node *cn);
+
+uint32_t update_metric(struct metric_record *mr, struct metric_algo *ma, SQN_T sqn_in,
SQN_T sqn_max, uint32_t probe);
+
+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 );
+
+
+IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T
neighIID4neigh);
+
+IDM_T update_neighIID4x_repository(struct neigh_node *neigh, IID_T neighIID4x, struct
dhash_node *dhn);
+
+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 cleanup_all( int 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);
+
+
+/***********************************************************
+ Configuration data and handlers
+************************************************************/
+
+
+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 );
Added: trunk/bmx/control.c
===================================================================
--- trunk/bmx/control.c (rev 0)
+++ trunk/bmx/control.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,3324 @@
+/*
+ * 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.
+ *
+ * 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 <stdarg.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+
+#include "bmx.h"
+#include "plugin.h"
+#include "schedule.h"
+
+
+
+#define MAX_DBG_STR_SIZE 1500
+
+static char run_dir[MAX_PATH_SIZE] = DEF_RUN_DIR;
+
+static int32_t debug_level = -1;
+static int32_t dbg_mute_to;
+
+#define MIN_LOOP_INTERVAL 100
+#define MAX_LOOP_INTERVAL 10000
+#define DEF_LOOP_INTERVAL 1000
+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 );
+
+struct list_head dbgl_clients[DBGL_MAX+1];
+static struct dbg_histogram dbgl_history[2][DBG_HIST_SIZE];
+
+static uint8_t debug_system_active = NO;
+
+
+static char *init_string = NULL;
+
+static int32_t Testing = NO;
+int32_t Load_config;
+
+char *prog_name;
+
+struct opt_type Patch_opt;
+
+LIST_SIMPEL( opt_list, struct opt_data, list ); // global opt_list
+
+
+int32_t Client_mode = NO; //this one must be initialized manually!
+
+static void remove_dbgl_node( struct ctrl_node *cn ) {
+
+ int8_t i;
+ struct dbgl_node *dn;
+ struct list_node *list_pos, *list_tmp, *list_prev;
+
+ for ( i = DBGL_MIN; i <= DBGL_MAX; i++ ) {
+
+ list_prev = (struct list_node *)&dbgl_clients[i];
+
+ list_for_each_safe( list_pos, list_tmp, (struct list_node *)&dbgl_clients[i] ) {
+
+ dn = list_entry(list_pos, struct dbgl_node, list);
+
+ if ( dn->cn == cn ) {
+ list_del_next(&dbgl_clients[i], list_prev);
+ debugFree( list_pos, -300049 );
+ } else {
+ list_prev = &dn->list;
+ }
+ }
+ }
+
+ cn->dbgl = -1;
+}
+
+
+static void add_dbgl_node( struct ctrl_node *cn, int dbgl ) {
+
+ if ( !cn || dbgl < DBGL_MIN || dbgl > DBGL_MAX )
+ return;
+
+ struct dbgl_node *dn = debugMalloc( sizeof( struct dbgl_node ), -300009 );
+ memset( dn, 0, sizeof( struct dbgl_node ) );
+
+ dn->cn = cn;
+ cn->dbgl = dbgl;
+ list_add_tail(&dbgl_clients[dbgl], &dn->list);
+
+ if ( dbgl == DBGL_SYS || dbgl == DBGL_CHANGES ) {
+ dbg( DBGL_CHANGES, DBGT_INFO, "resetting muted dbg history" );
+ memset( dbgl_history, 0, sizeof( dbgl_history ) );
+ }
+
+}
+
+
+static int daemonize() {
+
+ int fd;
+
+ switch( fork() ) {
+
+ case -1:
+ return -1;
+
+ case 0:
+ break;
+
+ default:
+ exit(EXIT_SUCCESS);
+
+ }
+
+ if ( setsid() == -1 )
+ return -1;
+
+ /* Ensure we are no session leader */
+ if ( fork() )
+ exit(EXIT_SUCCESS);
+
+
+ errno=0;
+ if ( chdir( "/" ) < 0 ) {
+ dbg( DBGL_SYS, DBGT_ERR, "could not chdir to /: %s", strerror(errno) );
+ }
+
+ if ( ( fd = open( _PATH_DEVNULL, O_RDWR, 0) ) != -1 ) {
+
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+
+ if ( fd > 2 )
+ close(fd);
+
+ }
+
+ return 0;
+
+}
+
+static int update_pid_file( void ) {
+
+ char tmp_path[MAX_PATH_SIZE+20] = "";
+ int tmp_fd = 0;
+
+ My_pid = getpid();
+
+ sprintf( tmp_path, "%s/pid", run_dir );
+
+ if ( (tmp_fd = open( tmp_path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
)) < 0 ) { //check permissions of generated file
+
+ dbgf( DBGL_SYS, DBGT_ERR, "could not open %s - %s", tmp_path, strerror(errno)
);
+ return FAILURE;
+ }
+
+ dprintf( tmp_fd, "%d\n", My_pid );
+
+ close ( tmp_fd );
+ return SUCCESS;
+}
+
+static void activate_debug_system( void ) {
+
+ if ( !debug_system_active ) {
+
+ /* daemonize */
+ if ( debug_level == -1 ) {
+
+ if ( daemonize() < 0 ) {
+ dbg( DBGL_SYS, DBGT_ERR, "can't fork to background: %s",
strerror(errno) );
+ cleanup_all( -500093 );
+ }
+
+ // fork will result in a new pid
+ if ( update_pid_file() == FAILURE )
+ cleanup_all( -500132 );
+
+
+ } else {
+
+ struct ctrl_node *cn = create_ctrl_node( STDOUT_FILENO, NULL, NO/*admin rights not
necessary*/ );
+
+ add_dbgl_node( cn, debug_level );
+
+ }
+
+ //dbg( DBGL_CHANGES, DBGT_INFO, "resetting muted dbg history" );
+ memset( dbgl_history, 0, sizeof( dbgl_history ) );
+
+ 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);
+
+ }
+}
+
+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) );
+
+ list_add_tail(&ctrl_list, &cn->list);
+
+ cn->fd = fd;
+ cn->cn_fd_handler = cn_fd_handler;
+ cn->dbgl = -1;
+ cn->authorized = authorized;
+
+ return cn;
+}
+
+
+void close_ctrl_node( uint8_t cmd, struct ctrl_node *ctrl_node ) {
+
+ struct list_node* list_pos, *list_prev, *list_tmp;
+ int trash;
+
+ list_prev = (struct list_node *)&ctrl_list;
+
+ list_for_each_safe( list_pos, list_tmp, &ctrl_list ) {
+
+ struct ctrl_node *cn = list_entry(list_pos, struct ctrl_node, list);
+
+ if ( ( cmd == CTRL_CLOSE_ERROR || cmd == CTRL_CLOSE_SUCCESS || cmd == CTRL_CLOSE_DELAY
) && cn == ctrl_node ) {
+
+ if ( cn->fd > 0 && cn->fd != STDOUT_FILENO ) {
+
+ cn->closing_stamp = MAX(bmx_time,1);
+ remove_dbgl_node( cn );
+
+ //leaving this after remove_dbgl_node() prevents debugging via broken -d4 pipe
+ dbgf_all( DBGT_INFO, "closed ctrl node fd %d with cmd %d", cn->fd, cmd
);
+
+
+ if ( cmd == CTRL_CLOSE_SUCCESS )
+ trash=write( cn->fd, CONNECTION_END_STR, strlen(CONNECTION_END_STR) );
+
+ if ( cmd != CTRL_CLOSE_DELAY ) {
+ close( cn->fd );
+ cn->fd = 0;
+ change_selects();
+ }
+
+ }
+
+ return;
+
+ } 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 ) ) )
+ {
+
+ if ( cn->fd > 0 && cn->fd != STDOUT_FILENO ) {
+ remove_dbgl_node( cn );
+ //leaving this after remove_dbgl_node() prevents debugging via broken -d4 pipe
+ dbgf_all( DBGT_INFO, "closed ctrl node fd %d", cn->fd );
+
+ close( cn->fd );
+ cn->fd = 0;
+ change_selects();
+ }
+
+ list_del_next(&ctrl_list, list_prev);
+ debugFree( cn, -300050 );
+
+ } else {
+
+ list_prev = (struct list_node *)&cn->list;
+
+ }
+ }
+}
+
+
+void accept_ctrl_node( void ) {
+
+ struct sockaddr addr;
+ socklen_t addr_size = sizeof(struct sockaddr);
+ int32_t unix_opts;
+
+ int fd = accept( unix_sock, (struct sockaddr *)&addr, &addr_size);
+
+ if ( fd < 0 ) {
+ dbg( DBGL_SYS, DBGT_ERR, "can't accept unix client: %s", strerror(errno)
);
+ return;
+ }
+
+ /* make unix socket non blocking */
+ unix_opts = fcntl( fd, F_GETFL, 0 );
+ fcntl( fd, F_SETFL, unix_opts | O_NONBLOCK );
+
+ create_ctrl_node( fd, NULL, YES );
+
+ change_selects();
+
+ dbgf_all( DBGT_INFO, "got unix control connection" );
+
+}
+
+
+
+void handle_ctrl_node( struct ctrl_node *cn ) {
+ char buff[MAX_UNIX_MSG_SIZE+1];
+
+ if ( cn->cn_fd_handler ) {
+ (cn->cn_fd_handler) (cn);
+ return;
+ }
+
+ errno=0;
+ int input = read( cn->fd, buff, MAX_UNIX_MSG_SIZE );
+
+ buff[input]='\0';
+
+ if ( input > 0 && input < MAX_UNIX_MSG_SIZE ) {
+
+ dbgf_all( DBGT_INFO, "rcvd ctrl stream via fd %d, %d bytes, auth %d: %s",
+ cn->fd, input, cn->authorized, buff );
+
+ if ( (apply_stream_opts( buff, OPT_CHECK, NO/*no cfg by default*/, cn ) == FAILURE)
||
+ (apply_stream_opts( buff, OPT_APPLY, NO/*no cfg by default*/, cn ) == FAILURE) )
+ {
+
+ dbg( DBGL_SYS, DBGT_ERR, "invalid ctrl stream via fd %d, %d bytes, auth %d:
%s",
+ cn->fd, input, cn->authorized, buff );
+
+ close_ctrl_node( CTRL_CLOSE_ERROR, cn );
+ return;
+ }
+
+ respect_opt_order( OPT_APPLY, 0, 99, NULL, NO/*load_cofig*/, OPT_POST, 0/*probably
closed*/ );
+
+ cb_plugin_hooks( NULL, PLUGIN_CB_CONF );
+
+ } else {
+
+ close_ctrl_node( CTRL_CLOSE_STRAIGHT, cn );
+
+ //leaving this after close_ctrl_node() -> remove_dbgl_node() prevents debugging via
broken -d4 pipe
+ dbgf_all( DBGT_INFO, "closed fd %d, rcvd %d bytes, auth %d: %s",
+ cn->fd, input, cn->authorized, buff );
+
+ }
+
+ return;
+}
+
+
+#ifndef TESTDEBUG
+
+// 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 int r=0;
+ int i, unused_i, h;
+
+ check_len = MIN(check_len, DBG_HIST_TEXT_SIZE);
+
+ if ( !strlen(s) || !dbg_mute_to || !check_len )
+ return DBG_HIST_NEW;
+
+ if ( dbgl == DBGL_SYS )
+ h=0;
+
+ else if ( dbgl == DBGL_CHANGES )
+ h=1;
+
+ else
+ return DBG_HIST_NEW;
+
+
+ unused_i = -1;
+ i = r = (r+1) % DBG_HIST_SIZE;
+
+ do {
+
+ if ( dbgl_history[h][i].check_len == 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 ) )
+ {
+
+ dbgl_history[h][i].catched++;
+
+ if ( dbgl_history[h][i].catched == 2 )
+ return DBG_HIST_MUTING;
+
+ else
+ return DBG_HIST_MUTED;
+
+ }
+
+ dbgl_history[h][i].print_stamp = bmx_time;
+ dbgl_history[h][i].catched = 1;
+ return DBG_HIST_NEW;
+
+ }
+
+ 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 ) ) ) )
+ {
+
+ unused_i = i;
+ }
+
+
+ i = ( (i+1) % DBG_HIST_SIZE );
+
+ } while ( i != r );
+
+ if ( unused_i == -1 )
+ unused_i = r;
+
+ dbgl_history[h][unused_i].expire = dbg_mute_to;
+ dbgl_history[h][unused_i].check_len = check_len;
+ dbgl_history[h][unused_i].print_stamp = bmx_time;
+ dbgl_history[h][unused_i].catched = 1;
+ memcpy( dbgl_history[h][unused_i].text, s, MIN( check_len, strlen(s) ) );
+
+ return DBG_HIST_NEW;
+
+}
+
+
+
+#define MAX_DBG_WRITES 4
+void dbg_printf( struct ctrl_node *cn, char *last, ... ) {
+
+ if ( !cn || cn->fd <= 0 )
+ return;
+
+ static char s[ MAX_DBG_STR_SIZE + 1 ];
+ ssize_t w, out=0;
+ int i = 1;
+
+ va_list ap;
+ va_start( ap, last );
+ vsnprintf( s, MAX_DBG_STR_SIZE, last, ap );
+ va_end( ap );
+
+ // CONNECTION_END_CHR is reserved for signaling connection end
+ paranoia( -500146, (strchr( s, CONNECTION_END_CHR ) ) );
+
+ errno=0;
+
+ while ( (w=write( cn->fd, s+out, strlen(s+out) )) != (ssize_t)strlen(s+out) ) {
+
+ if ( errno == EPIPE || i >= MAX_DBG_WRITES || cn->dbgl==DBGL_ALL ) {
+
+ if ( cn->dbgl != DBGL_ALL ) {
+ syslog( LOG_ERR, "failed %d times writing %d instead of %d/%d bytes (%s)! Giving
up: %s\n",
+ i, (int)w, (int)strlen(s+out), (int)strlen(s), strerror(errno), s+out );
+ }
+
+ break;
+ }
+ i++;
+
+ wait_sec_msec( 0, 10 );
+
+ if( w > 0 )
+ out+=w;
+
+ errno=0;
+ }
+}
+
+
+static void debug_output ( uint32_t check_len, struct ctrl_node *cn, int8_t dbgl, int8_t
dbgt, char const *f, char *s ) {
+
+ static uint16_t dbgl_all_msg_num = 0;
+ static char *dbgt2str[] = {"", "INFO ", "WARN ",
"ERROR "};
+
+ struct list_node *list_pos;
+ int16_t dbgl_out[DBGL_MAX+1];
+ int i = 0, j;
+
+ uint8_t mute_dbgl_sys = DBG_HIST_NEW;
+ uint8_t mute_dbgl_changes = DBG_HIST_NEW;
+
+
+ if ( cn && cn->fd != STDOUT_FILENO )
+ dbg_printf( cn, "%s%s%s%s\n", dbgt2str[dbgt], f?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 )
+ syslog( LOG_ERR, "%s%s%s%s\n", dbgt2str[dbgt], f?f:"", f?"():
":"", s );
+
+ return;
+ }
+
+
+ if ( dbgl == DBGL_ALL ) {
+
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_ALL ] ) ) dbgl_out[i++] = DBGL_ALL;
+
+ } else if ( dbgl == DBGL_CHANGES ) {
+
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_CHANGES ] ) ) dbgl_out[i++] =
DBGL_CHANGES;
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_ALL ] ) ) dbgl_out[i++] = DBGL_ALL;
+
+ } else if ( dbgl == DBGL_TEST ) {
+
+ 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_PROFILE ) {
+
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_PROFILE ] ) ) dbgl_out[i++] =
DBGL_PROFILE;
+
+ } else if ( dbgl == DBGL_SYS ) {
+
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_SYS ] ) ) dbgl_out[i++] = DBGL_SYS;
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_CHANGES ] ) ) dbgl_out[i++] =
DBGL_CHANGES;
+ if ( !LIST_EMPTY( &dbgl_clients[DBGL_ALL ] ) ) dbgl_out[i++] = DBGL_ALL;
+
+ if ( check_len )
+ mute_dbgl_sys = check_dbg_history( DBGL_SYS, s, check_len );
+
+ if ( mute_dbgl_sys != DBG_HIST_MUTED )
+ syslog( LOG_ERR, "%s%s%s%s\n", dbgt2str[dbgt], f?f:"", f?"():
":"", s );
+
+ if ( mute_dbgl_sys == DBG_HIST_MUTING )
+ syslog( LOG_ERR, "%smuting further messages (with equal first %d bytes) for at
most %d seconds\n",
+ dbgt2str[DBGT_WARN], check_len, dbg_mute_to/1000 );
+
+ }
+
+ for ( j = 0; j < i; j++ ) {
+
+ int level = dbgl_out[j];
+
+ if ( level == DBGL_ALL )
+ dbgl_all_msg_num++;
+
+ if ( level == DBGL_CHANGES && check_len &&
+ (mute_dbgl_changes = check_dbg_history( DBGL_CHANGES, s, check_len )) ==
DBG_HIST_MUTED )
+ continue;
+
+ if ( level == DBGL_SYS && mute_dbgl_sys == DBG_HIST_MUTED )
+ continue;
+
+
+ list_for_each ( list_pos, (struct list_node *)&(dbgl_clients[level]) ) {
+
+ struct dbgl_node *dn = list_entry(list_pos, struct dbgl_node, list);
+
+ if ( !dn->cn || dn->cn->fd <= 0 )
+ continue;
+
+ if ( level == DBGL_CHANGES ||
+ level == DBGL_TEST ||
+ 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 );
+
+ if ( ( level == DBGL_SYS && mute_dbgl_sys == DBG_HIST_MUTING ) ||
+ ( level == DBGL_CHANGES && mute_dbgl_changes == DBG_HIST_MUTING ) )
+ dbg_printf( dn->cn,
+ "[%d %8u] %smuting further messages (with equal first %d bytes) for at
most %d seconds\n",
+ My_pid, bmx_time, dbgt2str[DBGT_WARN], check_len, dbg_mute_to/1000 );
+
+ }
+ }
+}
+
+
+
+// this static array of char is used by all following dbg functions.
+static char dbg_string_out[ MAX_DBG_STR_SIZE + 1 ];
+
+void dbg ( int8_t dbgl, int8_t dbgt, char *last, ... ) {
+ va_list ap;
+ va_start( ap, last );
+ vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap );
+ va_end( ap );
+ debug_output ( 0, 0, dbgl, dbgt, 0, dbg_string_out );
+}
+
+void _dbgf ( int8_t dbgl, int8_t dbgt, char const *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 ( 0, 0, dbgl, dbgt, f, dbg_string_out );
+}
+
+void dbg_cn ( struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char *last, ... ) {
+ va_list ap;
+ va_start( ap, last );
+ vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap );
+ va_end( ap );
+ 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, ... ) {
+ va_list ap;
+ va_start( ap, last );
+ vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap );
+ va_end( ap );
+ debug_output ( 0, cn, dbgl, dbgt, f, dbg_string_out );
+}
+
+void dbg_mute ( uint32_t check_len, int8_t dbgl, int8_t dbgt, 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, 0, dbg_string_out );
+}
+
+void _dbgf_all ( int8_t dbgt, char const *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 ( 0, 0, DBGL_ALL, dbgt, f, dbg_string_out );
+}
+
+uint8_t __dbgf_all( void ) {
+
+ if ( debug_level != DBGL_ALL && LIST_EMPTY( &dbgl_clients[DBGL_ALL] ) )
+ return NO;
+
+ return YES;
+}
+#endif
+
+
+
+
+
+
+
+int (*load_config_cb) ( uint8_t test, struct opt_type *opt, struct ctrl_node *cn ) =
NULL;
+
+int (*save_config_cb) ( uint8_t del, struct opt_type *opt, char *parent, char *val,
struct ctrl_node *cn ) = NULL;
+
+int (*derive_config) ( char *reference, char *derivation, struct ctrl_node *cn ) = NULL;
+
+
+void get_init_string( int g_argc, char **g_argv ) {
+
+ uint32_t size = 1, dbg_init_out = 0;
+ int i;
+ char *dbg_init_str;
+
+ for (i=0; i < g_argc; i++)
+ size+=( 1 + strlen( g_argv[i]) );
+
+ dbg_init_str = debugMalloc( size, -300012 );
+
+ for (i=0; i < g_argc; i++)
+ dbg_init_out = dbg_init_out + sprintf( (dbg_init_str + dbg_init_out), "%s ",
g_argv[i] );
+
+ init_string = dbg_init_str;
+}
+
+
+static void free_init_string ( void ) {
+
+ if ( init_string )
+ debugFree( init_string, -300052 );
+
+ 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 ) {
+
+ char c = opt->short_name;
+
+ if ( cmd == OPT_ADJUST )
+ dbg( DBGL_SYS, DBGT_WARN, "option --%s%s%c%sis DEPRECATED and ignored!",
+ opt->long_name, c?", -":"", c?c:' ', c?"
":"" );
+
+ return SUCCESS;
+}
+#endif
+
+
+
+
+
+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 )
+ return FAILURE;
+
+ if ( !p || !(mc = get_opt_child(get_option(opt,0,ARG_MASK), p) ) || !mc->c_val )
+ return FAILURE;
+
+ sprintf( out, "%s/%s", nc->c_val, mc->c_val );
+
+ if ( str2netw( out, ip, '/', cn, mask, 32 ) == FAILURE )
+ return FAILURE;
+
+ return SUCCESS;
+}
+
+
+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;
+ struct opt_parent *p;
+
+ 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 );
+ return FAILURE;
+ }
+
+ // obtain netmask:
+
+ p = get_opt_parent_val( opt, patch->p_val );
+
+ if ( (mc = get_opt_child( get_option(opt,0,ARG_MASK), patch ) ) &&
mc->c_val ) {
+
+ // obtain the just-given netmask:
+
+ if ( str2netw( mc->c_val, ip, '/', cn, 0,0 ) == SUCCESS ) {
+
+ // the 255.255.255.0 notation:
+
+ if ( *ip == htonl( 0xFFFFFFFF<<( 32 - (*mask=bits_count( *ip )) ) ) ) {
+ 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 );
+ return FAILURE;
+ }
+
+ } else if ( (*mask=strtol(mc->c_val, NULL, 10)) ) {
+
+ // 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 );
+ 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 );
+ return FAILURE;
+ }
+
+ } else if ( p && (mc = get_opt_child(get_option(opt,0,ARG_MASK), 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 );
+ return FAILURE;
+ }
+
+
+ // obtain the network:
+
+ if ((nc = get_opt_child(get_option(opt, 0, ARG_NETW), 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 );
+ return FAILURE;
+ }
+
+ set_opt_child_val( nc, ipStr( validate_net_mask( *ip, *mask, 0 ) ) );
+
+ } else if ( p && (nc=get_opt_child( get_option(opt,0,ARG_NETW), 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 );
+ return FAILURE;
+ }
+
+ } else {
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing %s %s /%s",
+ opt->long_name, patch->p_val, ARG_NETW );
+
+ return FAILURE;
+ }
+
+ sprintf( out, "%s/%d", nc->c_val, *mask );
+ return SUCCESS;
+}
+
+static char* nextword( char *s ) {
+
+ uint32_t i = 0;
+ uint8_t found_gap = NO;
+
+ if ( !s )
+ return NULL;
+
+ for( i=0; i<strlen(s); i++ ) {
+
+ if ( s[i] == '\0' || s[i] == '\n' )
+ return NULL;
+
+ if ( !found_gap && ( s[i]==' ' || s[i]=='\t' ))
+ found_gap = YES;
+
+ if ( found_gap && ( s[i]!=' ' && s[i]!='\t' ) )
+ return &(s[i]);
+
+ }
+
+ return NULL;
+
+}
+
+static char *debugWordDup( char* word, int32_t tag ) {
+
+ if ( !word )
+ return NULL;
+
+ char *ret = debugMalloc( wordlen(word)+1, tag );
+ snprintf( ret, wordlen(word)+1, "%s", word );
+ return ret;
+}
+
+
+
+
+static void strchange( char *s, char i, char o ) {
+
+ char *p;
+ while ( s && (p=strchr( s, i )) )
+ p[0] = o;
+
+}
+
+
+static int32_t end_of_cmd_stream( struct opt_type *opt, char *s ) {
+
+ char test[MAX_ARG_SIZE]="";
+ snprintf( test, wordlen(s)+1, "%s", s );
+ strchange( test, '-', '_' );
+
+ if ( opt->opt_t != A_PS0 )
+ s = nextword(s);
+ else if ( wordlen(s)>1 && !strncasecmp( test, opt->long_name,
wordlen(opt->long_name) ) )
+ s = nextword(s);
+ else if ( wordlen(s)>1 )
+ s = s+1;
+ else
+ s = nextword(s);
+
+ if ( s && ( s[0] != EOS_DELIMITER || wordlen(s)>1 ) )
+ return NO;
+
+ return YES;
+
+}
+
+
+static int8_t is_valid_opt_ival( struct opt_type *opt, char *s, struct ctrl_node *cn ) {
+
+ if ( opt->imin == opt->imax )
+ return SUCCESS;
+
+ char* invalids = NULL;
+
+ errno=0;
+ int ival = strtol(s, &invalids , 10);
+
+ if ( wordlen(s) < 1 ||
+ ival < opt->imin || ival > opt->imax ||
+ invalids!=(s+wordlen(s)) ||
+ errno == ERANGE || errno == EINVAL )
+ {
+
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s value %d is invalid! Must be %d <=
<value> <= %d !",
+ opt->long_name, ival, opt->imin, opt->imax );
+
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+/*
+ * 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 ) )
+{
+
+ struct list_node *list_pos;
+
+ list_for_each( list_pos, &opt_list ) {
+
+ struct opt_type *opt = (struct opt_type *)list_entry( list_pos, struct opt_data, list
);
+
+ if ( /* !opt->help || we are also interested in uncommented configurations*/
!opt->long_name )
+ continue;
+
+ struct list_node *p_pos;
+
+ list_for_each( p_pos, &(opt->d.parents_instance_list) ) {
+
+ struct opt_parent *p = (struct opt_parent*)list_entry( p_pos, struct opt_parent, list
);
+
+ if ( (*func)( cn, data, opt, p, NULL ) == FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR,
+ "func()=%s with %s %s failed",
+ func_name, opt->long_name, p->p_val );
+
+ return FAILURE;
+ }
+
+ struct list_node *c_pos;
+
+ list_for_each( c_pos, &p->childs_instance_list ) {
+
+ struct opt_child *c = (struct opt_child*)list_entry( c_pos, struct opt_child, list
);
+
+ if ( (*func)( cn, data, opt, p, c ) == FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR,
+ "func()=%s with %s %s %s %s failed",
+ func_name, opt->long_name, p->p_val, c->c_opt->long_name,
c->c_val );
+
+ return FAILURE;
+ }
+ }
+ }
+ }
+
+ return SUCCESS;
+}
+
+
+static 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",
+ 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, "\n");
+ //dbg_printf(cn, "\nValid options are:\n" );
+
+ struct list_node *list_pos;
+
+ list_for_each( list_pos, &opt_list ) {
+
+ struct list_node *pos;
+ struct opt_type *opt = (struct opt_type *)list_entry( list_pos, struct opt_data, list
);
+ char sn[5], st[3 * MAX_ARG_SIZE], defaults[100];
+
+ 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 ) {
+
+
+ if ( opt->short_name )
+ snprintf( sn,5, ", -%c", opt->short_name );
+ else
+ *sn = '\0';
+
+ sprintf( st, "--%s%s %s ", opt->long_name, sn, opt->syntax ?
opt->syntax: "" );
+
+ if ( opt->opt_t != A_PS0 && opt->imin != opt->imax )
+ sprintf( defaults, "def: %-6d range: [ %d %s %d ]",
+ opt->idef, opt->imin, opt->imin+1 == opt->imax ? ",":
"...", opt->imax );
+ else
+ defaults[0]='\0';
+
+ dbg_printf( cn, "\n%-40s %s\n", st, defaults );
+
+ if ( verbose )
+ dbg_printf( cn, " %s\n", opt->help );
+
+
+
+ } else if ( !opt->long_name && opt->help ) {
+
+ dbg_printf( cn, "\n%s \n",opt->help );
+
+ }
+
+
+ list_for_each( pos, &opt->d.childs_type_list ) {
+
+ struct opt_type *c_opt = (struct opt_type *)list_entry( pos, struct opt_data, list );
+
+ 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 );
+ else
+ *sn = '\0';
+
+ sprintf( st, " /%s%s %s ", 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 ]",
+ c_opt->idef, c_opt->imin, c_opt->imin+1 == c_opt->imax ?
",": "...", c_opt->imax );
+ else
+ defaults[0]='\0';
+
+ dbg_printf( cn, "%-40s %s\n", st, defaults );
+
+ if ( verbose )
+ dbg_printf( cn, " %s\n", c_opt->help );
+
+ }
+ }
+
+ 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",
+ BMX_ENV_LIB_PATH, prog_name );
+
+ dbg_printf(cn, "\t%s\n", BMX_ENV_LIB_PATH );
+ dbg_printf(cn, "\t%s\n", BMX_ENV_DEBUG );
+ }
+
+ dbg_printf( cn, "\n");
+
+}
+
+void register_option( struct opt_type *opt ) {
+
+ dbgf_all( DBGT_INFO, "%s", (opt&&opt->long_name) ?
opt->long_name : "" );
+
+ struct opt_type *tmp_opt = NULL;
+ struct list_node *tmp_pos;
+
+ // these are the valid combinations:
+ if ( !(
+ //ival is validated and if valid assigned by call_option()
+ ( (opt->ival) && (opt->call_custom_option) &&
(opt->long_name) ) ||
+ //ival is validated and if valid assigned
+ ( (opt->ival) && !(opt->call_custom_option) &&
(opt->long_name) ) ||
+ //call_option() is called
+ ( !(opt->ival) && (opt->call_custom_option) &&
(opt->long_name) ) ||
+ //
+ ( !(opt->ival) && !(opt->call_custom_option) &&
!(opt->long_name) && opt->help )
+ ) )
+ goto failure;
+
+
+ // arg_t A_PS0 with no function can only be YES/NO:
+ paranoia( -500111, ( opt->opt_t == A_PS0 && opt->ival && (
opt->imin != NO || opt->imax != YES || opt->idef != NO ) ) );
+
+ // arg_t A_PS0 can not be stored
+ paranoia( -500112, ( opt->opt_t == A_PS0 && opt->cfg_t != A_ARG ) );
+
+ paranoia( -500113, ( opt->order < 0 || opt->order > 99 ) );
+
+ paranoia( -500114, ( (opt->parent_name && strchr( opt->parent_name,
'-')) || (opt->long_name && strchr( opt->long_name,
'-')) ) );
+
+
+ memset( &(opt->d), 0, sizeof( struct opt_data ) );
+
+ if ( opt->ival )
+ *opt->ival = opt->idef;
+
+ if ( opt->parent_name ) {
+
+ list_for_each( tmp_pos, &opt_list ) {
+ tmp_opt = (struct opt_type *)list_entry( tmp_pos, struct opt_data, list );
+
+ if ( tmp_opt->long_name == opt->parent_name )
+ break;
+ else
+ tmp_opt = NULL;
+ }
+
+ if ( opt->opt_t != A_CS1 || !tmp_opt || tmp_opt->opt_t != A_PMN )
+ goto failure;
+
+ opt->d.parent_opt = tmp_opt;
+
+ list_add_tail( &tmp_opt->d.childs_type_list, &opt->d.list );
+
+ } else {
+
+ LIST_INIT_HEAD( opt->d.childs_type_list, struct opt_data, list);
+ LIST_INIT_HEAD( opt->d.parents_instance_list, struct opt_parent,
list);
+
+ if ( opt->order ) {
+
+ struct list_node *prev_pos = (struct list_node *)&opt_list;
+
+ list_for_each( tmp_pos, &opt_list ) {
+
+ tmp_opt = (struct opt_type *)list_entry( tmp_pos, struct opt_data, list );
+
+ if ( tmp_opt->order > opt->order ) {
+ list_add_after(&opt_list, prev_pos,
&opt->d.list);
+ break;
+ } else {
+ prev_pos = &tmp_opt->d.list;
+ tmp_opt = NULL;
+ }
+ }
+ }
+
+ if ( !tmp_opt)
+ list_add_tail(&opt_list, &opt->d.list);
+
+ }
+
+ if ( opt->call_custom_option && ((opt->call_custom_option)(
OPT_REGISTER, 0, opt, 0,0 )) == FAILURE ) {
+
+ dbgf( DBGL_SYS, DBGT_ERR, "%s failed!", opt->long_name );
+ goto failure;
+ }
+
+
+ return;
+
+failure:
+
+ dbgf( DBGL_SYS, DBGT_ERR, "invalid data, tmp_opt: %c %s - option %c %s",
+ (tmp_opt && tmp_opt->short_name)?tmp_opt->short_name:'?',
+ (tmp_opt && tmp_opt->long_name)?tmp_opt->long_name:"??",
+ (opt && opt->short_name)?opt->short_name:'?', (opt
&& opt->long_name) ?opt->long_name:"??" );
+
+ paranoia( -500091, YES );
+}
+
+
+static void remove_option( struct opt_type *opt ) {
+
+ struct list_node *tmp_pos, *list_pos, *prev_pos;
+
+ del_opt_parent( opt, NULL );
+
+ prev_pos = (struct list_node *)&opt_list;
+
+ list_for_each_safe( list_pos, tmp_pos, &opt_list ) {
+
+ struct opt_type *tmp_opt = (struct opt_type *)list_entry( list_pos, struct opt_data,
list );
+
+ if ( opt == tmp_opt ) {
+
+ if ( !opt->parent_name && opt->call_custom_option &&
+ ((opt->call_custom_option)( OPT_UNREGISTER, 0, opt, 0,0 )) == FAILURE )
+ {
+ dbgf( DBGL_SYS, DBGT_ERR, "%s failed!", opt->long_name );
+ }
+
+ list_del_next(&opt_list, prev_pos);
+ return;
+
+ } else {
+
+ prev_pos = &tmp_opt->d.list;
+
+ }
+
+ }
+
+ dbgf( DBGL_SYS, DBGT_ERR, "%s no matching opt found", opt->long_name );
+}
+
+
+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++]) );
+
+}
+
+/*
+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 list_node *list_pos;
+ int32_t len = 0;
+ struct list_head *list;
+ struct opt_type *opt = NULL;
+ char *equalp = NULL;
+ char s[MAX_ARG_SIZE]="";
+
+ if ( parent_opt && short_opt )
+ goto get_option_failure;
+
+ if ( !sin || wordlen(sin)+1 >= MAX_ARG_SIZE )
+ goto get_option_failure;
+
+ snprintf( s, wordlen(sin)+1, "%s", sin );
+ strchange( s, '-', '_' );
+
+ if ( short_opt )
+ len = 1;
+ else if ( (equalp = index( s, '=' )) && equalp < s+wordlen(s) )
+ len = equalp - s;
+ else
+ len = wordlen(s);
+
+
+ if ( parent_opt == NULL )
+ list = &opt_list;
+ else
+ list = &parent_opt->d.childs_type_list;
+
+ dbgf_all( DBGT_INFO, "searching %s", s );
+
+ list_for_each( list_pos, list ) {
+
+ opt = (struct opt_type *)list_entry( list_pos, struct opt_data, list );
+
+ if ( !opt->long_name )
+ continue;
+
+ 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 )
+ break;
+
+ else if ( !short_opt && len == 1 && s[0] == opt->short_name
&& !on_the_fly && opt->dyn_t != A_DYN )
+ break;
+
+ else if ( short_opt && s[0] == opt->short_name && on_the_fly
&& opt->dyn_t != A_INI )
+ break;
+
+ else if ( short_opt && s[0] == opt->short_name && !on_the_fly
&& opt->dyn_t != A_DYN )
+ break;
+
+
+ opt = NULL;
+ }
+
+ if ( opt && opt->long_name ) {
+ dbgf_all( DBGT_INFO,
+ "Success! short_opt %d, opt: %s %c, type %d, dyn %d, ival %d, imin %d,
imax %d, idef %d",
+ short_opt, opt->long_name ? opt->long_name : "-",
opt->short_name ? opt->short_name : '-',
+ opt->opt_t, opt->dyn_t,
+ opt->ival ? *opt->ival : 0, opt->imin, opt->imax, opt->idef
);
+
+ return opt;
+ }
+
+
+get_option_failure:
+
+ dbgf_all( DBGT_WARN, "Failed! called with parent %s, opt %c %s, len %d",
+ parent_opt?"YES":"NO", (short_opt ? s[0]: '-'),
(!short_opt ? s : "-"), len );
+
+ return NULL;
+
+}
+
+
+
+struct opt_child *get_opt_child ( struct opt_type *opt, struct opt_parent *p ) {
+
+ struct list_node *pos;
+
+ paranoia( -500026, ( opt->opt_t != A_CS1 ) );
+
+ paranoia( -500119, ( !p ) );
+
+
+ list_for_each( pos, &(p->childs_instance_list) ) {
+
+ struct opt_child *c = list_entry( pos, struct opt_child, list );
+
+ if ( c->c_opt == opt )
+ return c;
+
+ }
+
+ return NULL;
+}
+
+void set_opt_child_val( struct opt_child *c, char *val ) {
+
+ if ( val && c->c_val && wordsEqual( c->c_val, val ) )
+ return;
+
+ if ( c->c_val )
+ debugFree( c->c_val, -300053 );
+
+ c->c_val = NULL;
+
+ if ( val)
+ c->c_val = debugWordDup(val, -300013);
+}
+
+static void set_opt_child_ref( struct opt_child *c, char *ref ) {
+
+ if ( ref && c->c_ref && wordsEqual( c->c_ref, ref ) )
+ return;
+
+ if ( c->c_ref )
+ debugFree( c->c_ref, -300054 );
+
+ c->c_ref = NULL;
+
+ if ( 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 ) {
+
+ struct opt_child *c = list_entry( pos, struct opt_child, list );
+
+ list_del_next(&p->childs_instance_list, prev);
+
+ set_opt_child_val( c, NULL );
+ set_opt_child_ref( c, NULL );
+
+ debugFree( pos, -300055 );
+ return;
+}
+
+static void del_opt_child( struct opt_parent *p, struct opt_type *opt ) {
+
+ struct list_node *pos, *tmp, *prev;
+
+ prev = (struct list_node*)&p->childs_instance_list;
+
+ list_for_each_safe( pos, tmp, &(p->childs_instance_list) ) {
+
+ struct opt_child *c = list_entry( pos, struct opt_child, list );
+
+ if ( !opt || c->c_opt == opt )
+ del_opt_child_save( prev, pos, p );
+ else
+ prev = pos;
+ }
+}
+
+static 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) );
+
+ c->c_opt = opt;
+ c->parent_instance = p;
+ list_add_tail(&p->childs_instance_list, &c->list);
+
+ return c;
+}
+
+
+
+
+void set_opt_parent_val( struct opt_parent *p, char *val ) {
+
+ if ( val && p->p_val && wordsEqual( p->p_val, val ) )
+ return;
+
+ if ( p->p_val )
+ debugFree( p->p_val, -300056 );
+
+ p->p_val = NULL;
+
+ if ( val)
+ p->p_val = debugWordDup( val, -300015 );
+}
+
+void set_opt_parent_ref( struct opt_parent *p, char *ref ) {
+
+ if ( ref && p->p_ref && wordsEqual( p->p_ref, ref ) )
+ return;
+
+ if ( p->p_ref )
+ debugFree( p->p_ref, -300057 );
+
+ p->p_ref = NULL;
+
+ if ( ref )
+ p->p_ref = debugWordDup( ref, -300016 );
+}
+
+
+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) );
+
+ LIST_INIT_HEAD( p->childs_instance_list, struct opt_child, list );
+
+ list_add_tail(&opt->d.parents_instance_list, &p->list);
+
+ return p;
+}
+
+static 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 );
+
+ list_del_next(&opt->d.parents_instance_list, prev);
+
+ del_opt_child( p, NULL );
+
+ set_opt_parent_val( p, NULL );
+ set_opt_parent_ref( p, NULL );
+
+ debugFree( p, -300058 );
+}
+
+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);
+
+ list_for_each_safe( pos, tmp, &(opt->d.parents_instance_list) ) {
+
+ struct opt_parent *p = list_entry( pos, struct opt_parent, list );
+
+ if ( !parent || p == parent )
+ del_opt_parent_save( opt, prev, pos );
+ else
+ prev = pos;
+ }
+}
+
+
+struct opt_parent *get_opt_parent_val ( struct opt_type *opt, char *val ) {
+
+ struct opt_parent *p = NULL;
+ struct list_node *pos;
+
+ paranoia( -500118, ( opt->cfg_t == A_ARG ) );
+
+// paranoia( -500117, ( (opt->opt_t == A_PS0 || opt->opt_t == A_PS1) &&
opt->d.found_parents > 1 ) );
+ paranoia( -500117, ( (opt->opt_t == A_PS0 || opt->opt_t == A_PS1) &&
opt->d.parents_instance_list.items > 1 ) );
+
+ list_for_each( pos, &(opt->d.parents_instance_list) ) {
+
+ p = list_entry( pos, struct opt_parent, list );
+
+ if ( !val || wordsEqual( p->p_val, val ) )
+ return p;
+
+ }
+
+ return NULL;
+}
+
+struct opt_parent *get_opt_parent_ref ( struct opt_type *opt, char *ref ) {
+
+ struct opt_parent *p = NULL;
+ struct list_node *pos;
+
+ paranoia( -500124, ( opt->cfg_t == A_ARG ) );
+
+// paranoia( -500116, ( (opt->opt_t == A_PS0 || opt->opt_t == A_PS1) &&
opt->d.found_parents > 1 ) );
+ paranoia( -500116, ( (opt->opt_t == A_PS0 || opt->opt_t == A_PS1) &&
opt->d.parents_instance_list.items > 1 ) );
+
+ list_for_each( pos, &(opt->d.parents_instance_list) ) {
+
+ p = list_entry( pos, struct opt_parent, list );
+
+ if ( ref && wordsEqual( p->p_ref, ref ) )
+ return p;
+
+ }
+
+ return NULL;
+}
+
+static 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 );
+ set_opt_parent_ref ( dup_p, p->p_ref );
+
+ dup_p->p_diff = p->p_diff;
+
+ struct list_node *pos;
+ list_for_each( pos, &(p->childs_instance_list) ) {
+
+ struct opt_child *c = list_entry( pos, struct opt_child, list );
+
+ struct opt_child *dup_c = add_opt_child( c->c_opt, dup_p );
+ set_opt_child_val( dup_c, c->c_val );
+ set_opt_child_ref( dup_c, c->c_ref );
+ }
+
+ return dup_p;
+}
+
+
+
+
+char *opt_cmd2str[] = {
+ "OPT_REGISTER",
+ "OPT_PATCH",
+ "OPT_ADJUST",
+ "OPT_CHECK",
+ "OPT_APPLY",
+ "OPT_SET_POST",
+ "OPT_POST",
+ "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 ret;
+
+ paranoia( -500102, ( (cmd != OPT_CHECK && cmd != OPT_APPLY) ||
opt->parent_name ) );
+
+ struct opt_parent *p = add_opt_parent( &Patch_opt );
+
+ if ((ret = call_option(del, OPT_PATCH, _save, opt, p, in, cn)) == FAILURE ||
+ call_option(del, OPT_ADJUST, _save, opt, p, in, cn) == FAILURE ||
+ call_option(del, cmd, _save, opt, p, in, cn) == FAILURE)
+ ret = FAILURE;
+
+ del_opt_parent( &Patch_opt, p );
+
+ dbgf_all( DBGT_INFO, "del:%d, %s, save:%d, %s %s returns: %d",
+ del, opt_cmd2str[cmd], _save, opt->long_name, in, ret );
+
+ return ret;
+}
+
+
+
+static 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 );
+
+ if ( opt->opt_t == A_PS0 ) {
+
+ patch->p_diff = ((ad==ADD) ? ADD : DEL);
+
+ } else if ( opt->opt_t == A_PS1 || opt->opt_t == A_PMN || opt->opt_t ==
A_CS1 ) {
+
+ char *ref = NULL;
+ char tmp[MAX_ARG_SIZE];
+
+ // assign one or more values
+ if ( ad == ADD || opt->opt_t == A_PMN ) {
+
+ if ( !strm || !wordlen(strm) || strm[0] == EOS_DELIMITER )
+ return FAILURE;
+
+ if ( strm && wordlen(strm) > strlen( REFERENCE_KEY_WORD ) &&
+ !strncmp( strm, REFERENCE_KEY_WORD, strlen( REFERENCE_KEY_WORD ) ) )
+ {
+ ref = strm;
+
+ if ( ad == ADD ) {
+
+ if ( !derive_config || derive_config( ref, tmp, cn ) == FAILURE ||
!wordlen(strm) ) {
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR,
+ "%s. Could not derive reference %s",
+ derive_config ? "invalid config" : "undefined
callback", strm );
+ return FAILURE;
+ }
+
+ strm = tmp;
+
+ } else if ( ad == DEL ) {
+
+ struct opt_parent *p_track = get_opt_parent_ref( opt, strm );
+
+ if ( !p_track || !p_track->p_val ) {
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR,
+ "Could not derive reference %s from tracked options", strm );
+ return FAILURE;
+ }
+
+ strm = p_track->p_val;
+ }
+ }
+
+ if ( is_valid_opt_ival( opt, strm, cn ) == FAILURE )
+ return FAILURE;
+
+ }
+
+ if ( opt->opt_t == A_PS1 || opt->opt_t == A_PMN ) {
+
+ set_opt_parent_val( patch, strm );
+ set_opt_parent_ref( patch, ref );
+
+ patch->p_diff = ((ad==ADD) ? ADD : DEL);
+
+ } else if ( opt->opt_t == A_CS1 ) {
+
+ struct opt_child *c = add_opt_child( opt, patch );
+
+ if ( ad == ADD )
+ set_opt_child_val( c, strm );
+
+ set_opt_child_ref( c, ref );
+ }
+ }
+
+ return SUCCESS;
+}
+
+
+static 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;
+
+ dbgf_all( DBGT_INFO, "del %d opt %s val %s", del, opt->long_name, val );
+
+ if ( opt->cfg_t == A_ARG )
+ return SUCCESS;
+
+ 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;
+
+
+ } else if ( opt->opt_t == A_PMN ) {
+
+ struct opt_parent *p_track = NULL;
+ struct list_node *c_pos, *c_tmp;
+ struct list_node *c_prev = (struct list_node*)&patch->childs_instance_list;
+
+ list_for_each_safe( c_pos, c_tmp, &patch->childs_instance_list ) {
+
+ struct opt_child *c = list_entry( c_pos, struct opt_child, list );
+ struct opt_child *c_track = NULL;
+ uint8_t c_del = c->c_val ? ADD : DEL;
+
+ p_track = NULL;
+
+ dbgf_all( DBGT_INFO, "p_val:%s", patch->p_val );
+
+ if ( (p_track = get_opt_parent_val( opt, val )) )
+ c_track = get_opt_child( c->c_opt, p_track );
+
+ if ( ( c_del && !c_track ) ||
+ ( !c_del && c_track && wordsEqual( c_track->c_val,
c->c_val ) ) )
+ {
+ del_opt_child_save( c_prev, c_pos, patch );
+ } else {
+ c_prev = c_pos;
+ }
+ }
+
+
+ p_track = get_opt_parent_val( opt, val );
+
+ if ( ( del && !p_track ) || ( !del && p_track ) )
+ patch->p_diff = NOP;
+
+ } else {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+
+static 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] = "";
+ int trash;
+
+ dbgf_all( DBGT_INFO, "cmd %s, opt_name %s, stream %s",
+ opt_cmd2str[cmd], opt->long_name, curr_strm_pos );
+
+ if ( cmd == OPT_CHECK || cmd == OPT_APPLY ) {
+
+ if ( !curr_strm_pos )
+ cleanup_all( -500141 );
+
+ sprintf( tmp_path, "%s/sock", run_dir );
+
+ struct sockaddr_un unix_addr;
+
+ memset( &unix_addr, 0, sizeof(struct sockaddr_un) );
+ unix_addr.sun_family = AF_LOCAL;
+ strcpy( unix_addr.sun_path, tmp_path );
+
+
+ if ( strlen( curr_strm_pos ) + 4 + strlen( ARG_TEST ) > sizeof( unix_buff ) ) {
+
+ dbg( DBGL_SYS, DBGT_ERR, "message too long: %s", curr_strm_pos );
+ cleanup_all( CLEANUP_FAILURE );
+ }
+
+ if ( cmd == OPT_CHECK )
+ return SUCCESS;
+
+ Client_mode = YES;
+
+ do {
+
+ dbgf_all( DBGT_INFO, "called with %s",curr_strm_pos);
+
+ if ( strlen(curr_strm_pos) > strlen(ARG_CONNECT) &&
+ !strncmp( curr_strm_pos, ARG_CONNECT, strlen(ARG_CONNECT) ) &&
+ (curr_strm_pos+strlen(ARG_CONNECT))[0] == ' ' )
+ {
+ sprintf( unix_buff, "%s %c", nextword(curr_strm_pos), EOS_DELIMITER );
+
+ } else if ( strlen(curr_strm_pos) > strlen(ARG_CONNECT) &&
+ !strncmp( curr_strm_pos, ARG_CONNECT, strlen(ARG_CONNECT) ) &&
+ (curr_strm_pos+strlen(ARG_CONNECT))[0] == '=' )
+ {
+ sprintf( unix_buff, "%s %c", curr_strm_pos+strlen(ARG_CONNECT)+1 ,
EOS_DELIMITER );
+
+ } else if ( strlen(curr_strm_pos) > 1 && curr_strm_pos[0] ==
opt->short_name && curr_strm_pos[1] == ' ' ) {
+ sprintf( unix_buff, "%s %c", nextword(curr_strm_pos), EOS_DELIMITER );
+
+ } else if ( strlen(curr_strm_pos) > 1 && curr_strm_pos[0] ==
opt->short_name && curr_strm_pos[1] != ' ' ) {
+ sprintf( unix_buff, "-%s %c", curr_strm_pos+1, EOS_DELIMITER );
+
+ } else {
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid connect stream
%s",curr_strm_pos);
+ return FAILURE;
+ }
+
+ unix_sock = socket( AF_LOCAL, SOCK_STREAM, 0 );
+
+ /* make unix_sock socket non blocking */
+ int sock_opts = fcntl( unix_sock, F_GETFL, 0 );
+ fcntl( unix_sock, F_SETFL, sock_opts | O_NONBLOCK );
+
+
+ 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 ?",
+ tmp_path, strerror(errno) );
+
+ cleanup_all( CLEANUP_FAILURE );
+
+ }
+
+ if ( write( unix_sock, unix_buff, strlen( unix_buff ) ) < 0 ) {
+
+ dbg( DBGL_SYS, DBGT_ERR, "can't write to unix socket: %s",
strerror(errno) );
+ cleanup_all( CLEANUP_FAILURE );
+
+ }
+
+ //printf("::::::::::::::::: from %s begin :::::::::::::::::::\n", tmp_path
);
+
+ if ( loop_mode )
+ trash=system( "clear" );
+
+ int32_t recv_buff_len = 0;
+
+ while ( !terminating() ) {
+
+ recv_buff_len = 0;
+
+ fd_set unix_wait_set;
+
+ FD_ZERO(&unix_wait_set);
+ FD_SET(unix_sock, &unix_wait_set);
+
+ struct timeval to = {0, 100000};
+
+ select( unix_sock+1, &unix_wait_set, NULL, NULL, &to );
+
+ if ( !FD_ISSET( unix_sock, &unix_wait_set ) )
+ continue;
+
+ do {
+ errno = 0;
+ recv_buff_len = read( unix_sock, unix_buff, MAX_UNIX_MSG_SIZE );
+
+ if ( recv_buff_len > 0 ) {
+
+ char *p;
+ unix_buff[recv_buff_len] = '\0';
+
+ if ( (p=strchr( unix_buff, CONNECTION_END_CHR )) ) {
+ *p='\0';
+ printf( "%s", unix_buff );
+ break;
+
+ }
+
+ printf( "%s", unix_buff );
+ }
+
+ } while ( recv_buff_len > 0 );
+
+ if ( recv_buff_len < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) )
+ continue;
+
+ if ( recv_buff_len < 0 ) {
+ dbgf(DBGL_SYS, DBGT_INFO, "sock returned %d errno %d: %s",
+ recv_buff_len, errno, strerror(errno) );
+ }
+
+ if ( recv_buff_len <= 0 )
+ cleanup_all( CLEANUP_FAILURE );
+
+ break;
+ }
+
+ close( unix_sock );
+ unix_sock = 0;
+
+ if ( loop_mode && !terminating() )
+ wait_sec_msec( loop_interval/1000, loop_interval%1000 );
+
+
+ } while ( loop_mode && !terminating() );
+
+ cleanup_all( CLEANUP_SUCCESS );
+
+
+ }
+
+ 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 ) {
+
+ char tmp_path[MAX_PATH_SIZE+20] = "";
+
+ if ( cmd == OPT_SET_POST && !on_the_fly ) {
+
+ // create unix sock:
+
+ struct sockaddr_un unix_addr;
+
+ sprintf( tmp_path, "%s/sock", run_dir );
+
+ memset( &unix_addr, 0, sizeof(struct sockaddr_un) );
+ unix_addr.sun_family = AF_LOCAL;
+ strcpy( unix_addr.sun_path, tmp_path );
+
+ // Testing for open and used unix socket
+
+ unix_sock = socket( AF_LOCAL, SOCK_STREAM, 0 );
+
+ if ( connect ( unix_sock, (struct sockaddr *)&unix_addr, sizeof(struct sockaddr_un)
) < 0 ) {
+
+ dbgf_all( DBGT_INFO, "found unbound %s, going to unlink and reuse!",
tmp_path );
+
+ close( unix_sock );
+ unlink( tmp_path );
+ unix_sock = socket( AF_LOCAL, SOCK_STREAM, 0 );
+
+ } else {
+
+ dbg( DBGL_SYS, DBGT_ERR,
+ "%s busy! Probably bmxd is already running! Use [--%s %s] -c ... to connect
to a running bmxd",
+ tmp_path, ARG_RUN_DIR, run_dir );
+ cleanup_all( CLEANUP_FAILURE );
+
+ }
+
+
+ if ( bind ( unix_sock, (struct sockaddr *)&unix_addr, sizeof (struct sockaddr_un) )
< 0 ) {
+
+ dbg( DBGL_SYS, DBGT_ERR, "can't bind unix socket '%s': %s",
tmp_path, strerror(errno) );
+ cleanup_all( CLEANUP_FAILURE );
+
+ }
+
+ if ( listen( unix_sock, 10 ) < 0 ) {
+
+ dbg( DBGL_SYS, DBGT_ERR, "can't listen unix socket '%s': %s",
tmp_path, strerror(errno) );
+ cleanup_all( CLEANUP_FAILURE );
+
+ }
+
+ if ( update_pid_file() == FAILURE )
+ return FAILURE;
+
+ }
+
+ 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 ) {
+
+ paranoia( -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 );
+
+ dbgf_all( DBGT_INFO, "%s save=%d %s p_diff=%d p_val:%s p_ref:%s strm:%s",
+ opt_cmd2str[cmd], save, opt->long_name, patch->p_diff, patch->p_val,
patch->p_ref, in );
+
+ if ( cleanup_patch( opt, patch, cn ) == FAILURE )
+ goto call_opt_apply_error;
+
+ if ( patch->p_diff == NOP && LIST_EMPTY(
&(patch->childs_instance_list) ) ) {
+ del_opt_parent( &Patch_opt, patch );
+ return SUCCESS;
+ }
+
+ // 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) ) {
+
+ 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" );
+
+ goto call_opt_apply_error;
+ }
+
+
+ if ( opt->call_custom_option == opt_connect ) {
+
+ if ( _opt_connect( cmd, opt, cn, in ) == FAILURE )
+ goto call_opt_apply_error;
+
+
+ } else if ( cmd == OPT_CHECK ) {
+
+ if ( opt->call_custom_option &&
+ (opt->call_custom_option)(OPT_CHECK, save, opt, patch, cn) ==
FAILURE) {
+
+ goto call_opt_apply_error;
+ }
+
+
+
+ } else if ( cmd == OPT_APPLY ) {
+
+ if ( opt->auth_t == A_ADM ) {
+
+ 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 );
+ }
+
+ if ( opt->ival && patch->p_diff == DEL )
+ *(opt->ival) = opt->idef;
+
+ else if ( opt->opt_t == A_PS0 && opt->ival &&
patch->p_diff == ADD )
+ *(opt->ival) = opt->imax;
+
+ else if ( opt->opt_t != A_PS0 && opt->ival &&
patch->p_diff == ADD )
+ *(opt->ival) = strtol( patch->p_val, NULL , 10 );
+
+ if ( opt->call_custom_option &&
+ (opt->call_custom_option)( OPT_APPLY, save, opt, patch, cn ) == FAILURE )
+ {
+
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR,
+ "failed setting the already succesfully tested option %s to %s",
+ opt->long_name, patch->p_val );
+
+ // this may happen when:
+ // - overwriting a config-file option with a startup-option (pain in the ass!)
+ // - configuring the same PMN option twice in one command-line
+ goto call_opt_apply_error;
+ }
+
+
+ }
+
+ del_opt_parent( &Patch_opt, patch );
+ return SUCCESS;
+
+call_opt_apply_error:
+
+ del_opt_parent( &Patch_opt, patch );
+ return FAILURE;
+}
+
+
+/* this table lists what could happen and how its' handled in track_opt_parent():
+
+patch tracked patch tracked config-
+p_val t_val p_ref t_ref -> file track
+ value: value: ref:
+
+DEL/0 x x x DEL DEL DEL | if ( !p_val && t_val )
+
+DEL/0 NULL x x NOP NOP NOP | else if ( !p_val && !t_val )
+
+A A A A NOP NOP NOP | else if ( p_val && p_val == t_val && p_ref
== t_ref )
+A A 0 0 NOP NOP NOP |
+
+ | else [if ( p_val && (p_val != t_val || p_ref != t_ref )]
+ |
+A A A B ref value ref | | if ( p_ref )
+A A A 0 ref value ref | |
+A B/NULL A A (*) ref value ref | |
+A B/NULL A B (-) ref value ref | |
+A B/NULL A 0 (-) ref value ref | |
+ |
+A A 0 B value value 0 | | else [if( !p_ref)]
+A B/NULL 0 0 value NOP 0 | |
+A B/NULL 0 A (*) value value 0 | |
+
+(*) in these cases, when configuring parent-options
+we have to reset the old (currently active) tracked t_val option
+before configuring the new patched p_val parent value
+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 ) {
+
+ 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 );
+ struct opt_parent *p_track = get_opt_parent_val( p_opt, p_opt->opt_t == A_PMN ?
p_patch->p_val : NULL );
+
+ paranoia( -500125, ( p_reftr && p_track && p_reftr != p_track ) );
+
+ p_track = p_track ? p_track : p_reftr;
+
+ dbgf_all( DBGT_INFO, "%s %s save=%d patch_diff:%d patch_val:%s patch_ref:%s
track_val:%s track_ref:%s",
+ opt_cmd2str[cmd], p_opt->long_name, save, p_patch->p_diff,
+ p_patch->p_val, p_patch->p_ref,
p_track?p_track->p_val:"-", p_track?p_track->p_ref:"-");
+
+ if ( p_patch->p_diff == DEL && p_track ) {
+
+ if ( cmd==OPT_APPLY ) {
+
+ if ( save && save_config_cb )
+ save_config_cb( DEL, p_opt, p_track->p_ref ? p_track->p_ref :
p_track->p_val, NULL, cn );
+
+ del_opt_parent( p_opt, p_track );
+ }
+
+ } else {
+
+ uint8_t changed = NO;
+
+ if ( p_patch->p_diff == DEL && !p_track ) {
+
+ if ( save ) {
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s %s does not exist",
p_opt->long_name, p_patch->p_val );
+ return FAILURE;
+ }
+
+ return SUCCESS;
+
+ } else if ( ( p_patch->p_diff == ADD && p_patch->p_val &&
p_track && wordsEqual( p_patch->p_val, p_track->p_val ) ) &&
+ ( ( p_patch->p_ref && p_track->p_ref &&
wordsEqual( p_patch->p_ref, p_track->p_ref) ) ||
+ ( !p_patch->p_ref && !p_track->p_ref ) ) )
+ {
+
+ } else if ( p_patch->p_val /*&& (patch_c->c_ref ||
!patch_c->c_ref)*/ ) {
+
+ if ( cmd == OPT_APPLY ) {
+
+ if ( !p_track ) {
+ p_track = add_opt_parent( p_opt );
+ set_opt_parent_val( p_track, p_patch->p_val );
+ set_opt_parent_ref( p_track, p_patch->p_ref );
+ }
+
+ if ( save && save_config_cb )
+ save_config_cb( ADD, p_opt,
+ p_track->p_ref ? p_track->p_ref : p_track->p_val,
+ p_patch->p_ref ? p_patch->p_ref : p_patch->p_val, cn );
+
+ set_opt_parent_val( p_track, p_patch->p_val );
+ set_opt_parent_ref( p_track, p_patch->p_ref );
+ }
+ changed=YES;
+
+ } else {
+ paranoia( -500121, YES );
+ }
+
+ if ( cmd == OPT_APPLY && changed && p_opt->auth_t == A_ADM )
+ dbg_cn( cn, DBGL_CHANGES, DBGT_INFO, "--%-22s %c%-30s",
+ p_opt->long_name, p_patch->p_diff==DEL?'-':' ',
p_patch->p_val);
+
+ if ( p_track ) {
+
+ list_for_each( pos, &p_patch->childs_instance_list ) {
+
+ uint8_t changed_child=NO;
+ char *save_val = p_track->p_ref ? p_track->p_ref : p_track->p_val;
+ struct opt_child *c_patch = list_entry( pos, struct opt_child, list );
+ struct opt_child *c_track = get_opt_child( c_patch->c_opt, p_track );
+
+
+ if ( !c_patch->c_val && c_track ) {
+
+ if ( cmd == OPT_APPLY ) {
+ if ( save && save_config_cb && c_track->c_opt->cfg_t !=
A_ARG )
+ save_config_cb( DEL, c_track->c_opt, save_val, c_track->c_ref ?
c_track->c_ref : c_track->c_val, cn );
+
+ del_opt_child( p_track, c_track->c_opt );
+ }
+ changed_child=changed=YES;
+
+ } 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 );
+ return FAILURE;
+ }
+
+ } else if ( ( c_patch->c_val && c_track &&
wordsEqual(c_patch->c_val, c_track->c_val) ) &&
+ ( ( c_patch->c_ref && c_track->c_ref &&
wordsEqual( c_patch->c_ref, c_track->c_ref) ) ||
+ ( !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 );
+
+ } else if ( c_patch->c_val ) {
+
+ if ( cmd == OPT_APPLY ) {
+ if ( save && save_config_cb && c_patch->c_opt->cfg_t !=
A_ARG )
+ save_config_cb( ADD, c_patch->c_opt, save_val, c_patch->c_ref ?
c_patch->c_ref : c_patch->c_val, cn );
+
+ if ( !c_track )
+ c_track = add_opt_child( c_patch->c_opt, p_track );
+
+ set_opt_child_val( c_track, c_patch->c_val );
+ set_opt_child_ref( c_track, c_patch->c_ref );
+ }
+
+ changed_child=changed=YES;
+
+ } else {
+
+ paranoia( -500122, YES );
+ }
+
+ 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,
+ 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 )
{
+
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s %s already configured",
+ p_opt->long_name, p_patch->p_val );
+
+ // actually here we can be pedantic or not because cleanup_patch()
+ // 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 ) {
+
+ 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 );
+
+ if ( !opt ) // might be NULL when referring to disabled plugin functionality
+ return SUCCESS;
+
+ paranoia( -500104, ( !( ad == ADD || ad == DEL ) ) );
+
+ paranoia( -500103, ( ( cmd == OPT_PATCH || cmd == OPT_ADJUST || cmd == OPT_CHECK ||
cmd == OPT_APPLY ) && !patch ) );
+
+ paranoia( -500147, ( ( cmd == OPT_PATCH || cmd == OPT_ADJUST || cmd == OPT_CHECK ||
cmd == OPT_APPLY ) && !cn ) );
+
+ if ( ( cmd == OPT_PATCH || cmd == OPT_ADJUST || cmd == OPT_CHECK || cmd ==
OPT_APPLY ) &&
+ !cn->authorized && opt->auth_t == A_ADM )
+ {
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "insufficient permissions to use command %s",
opt->long_name );
+ return FAILURE;
+ }
+
+ if ( ad == DEL && ( /*!on_the_fly this is what concurrent -r and -g
configurations do || */
+ /* opt->dyn_t == A_INI this is what conf-reload tries ||*/
opt->cfg_t == A_ARG ) ) {
+ dbg( DBGL_SYS, DBGT_ERR, "option %s can not be resetted during startup!",
opt->long_name );
+ return FAILURE;
+ }
+
+
+ if ( (opt->pos_t==A_END || opt->pos_t==A_ETE) && in &&
!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",
+ opt->long_name, opt->short_name?", -":"",
opt->short_name?opt->short_name:' ' );
+ }
+
+ goto call_option_failure;
+ }
+
+
+ if ( cmd == OPT_PATCH ) {
+
+ if ( (call_opt_patch( ad, opt, patch, in, cn )) == FAILURE )
+ goto call_option_failure;
+
+ if ( ( opt->pos_t == A_EAT || opt->pos_t == A_ETE ) && in )
+ return strlen( in );
+ else
+ return SUCCESS;
+
+
+ } else if ( cmd == OPT_ADJUST ) {
+
+ if ( opt->call_custom_option &&
+ ((opt->call_custom_option)( OPT_ADJUST, 0, opt, patch, cn )) == FAILURE )
+ goto call_option_failure;
+ else
+ return SUCCESS;
+
+
+ } else if ( cmd == OPT_CHECK || cmd == OPT_APPLY ) {
+
+ paranoia( -500105, ( opt->parent_name ) );
+
+ paranoia( -500128, ( opt->cfg_t != A_ARG && ( opt->opt_t == A_PMN ||
patch->p_diff != DEL ) && !patch->p_val ) );
+
+ if ( opt->cfg_t != A_ARG && opt->opt_t == A_PMN ) {
+
+ struct opt_parent *p_reftr = get_opt_parent_ref( opt, patch->p_ref );
+ struct opt_parent *p_track = get_opt_parent_val( opt, patch->p_val );
+
+ paranoia( -500129, ( p_reftr && p_track && p_reftr != p_track )
);
+
+ p_track = p_track ? p_track : p_reftr;
+
+ if ( ( patch->p_diff == ADD && patch->p_val && p_track
&&
+ !wordsEqual( patch->p_val, p_track->p_val ) ) &&
+ ( patch->p_ref || p_track->p_ref ) )
+ check_apply_parent_option( DEL, cmd, save, opt, p_track->p_val, cn );
+
+ }
+
+ if ( (call_opt_apply( cmd, save, opt, patch, in, cn )) == FAILURE )
+ goto call_option_failure;
+
+ if ( opt->cfg_t != A_ARG && track_opt_parent( cmd, save, opt, patch, cn )
== FAILURE )
+ goto call_option_failure;
+
+ return SUCCESS;
+
+
+ } else if ( cmd == OPT_SET_POST || cmd == OPT_POST ) {
+
+ if ( opt->call_custom_option && ((opt->call_custom_option)( cmd, 0,
opt, 0, cn )) == FAILURE )
+ goto call_option_failure;
+
+ return SUCCESS;
+ }
+
+
+call_option_failure:
+
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR,
+ "--%s %s Failed ! "
+ "( diff:%d ad:%d val:%d min:%d max:%d def:%d %s %d %d %d )",
+ 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) );
+
+ /* 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 ) ) {
+
+ dbg( DBGL_SYS, DBGT_ERR,
+ "ignored SYNTAX ERROR in startup configuration due to disabled --%s! FIX YOUR
CONFIG NOW !!",
+ ARG_PEDANTIC_CMDCHECK );
+
+ return SUCCESS;
+ }
+ */
+
+ 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 ) {
+
+ struct list_node *list_pos;
+ struct opt_type *opt;
+
+ dbgf_all( DBGT_INFO, "%s, cmd: %s, last %d, next %d, opt %s load %d",
+ opt_cmd2str[ test ], opt_cmd2str[ cmd ], last, next,
on?on->long_name:"???", load );
+
+ paranoia( -500002, ( test != OPT_CHECK && test != OPT_APPLY ) );
+
+ paranoia( -500107, ( cmd == OPT_CHECK || cmd == OPT_APPLY ) );
+
+
+ if ( next == 0 )
+ return last;
+
+ if ( last > next ) {
+
+ // debug which option caused the problems !
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR,
+ "--%s%s%c (order=%d option) MUST appear earlier in command
sequence!",
+ on?on->long_name:"???", on&&on->short_name?",
":"",on&&on->short_name?on->short_name:' ', next );
+
+ return FAILURE;
+ }
+
+ if ( last == next )
+ return next;
+
+
+ list_for_each( list_pos, &opt_list ) {
+
+ opt = (struct opt_type *)list_entry( list_pos, struct opt_data, list );
+
+ if ( load && opt->order >= last+1 && opt->order <= next
) {
+
+ if ( load_config_cb && load_config_cb( test, opt, cn ) == FAILURE ) {
+
+ dbgf_all( DBGT_ERR, "load_config_cb() %s failed",
+ opt->long_name );
+
+ return FAILURE;
+ }
+ }
+
+ if ( test == OPT_APPLY && opt->order >= last && opt->order
<= next-1 ) {
+
+ if ( call_option( ADD, cmd, 0/*save*/, opt, 0,0, cn ) == FAILURE ) {
+
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "call_option() %s cmd %s failed",
+ opt->long_name, opt_cmd2str[cmd] );
+
+ return FAILURE;
+ }
+ }
+ }
+
+ return next;
+}
+
+
+// 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 )
{
+
+ 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
+ };
+
+ char *state2str[] =
{"NEXT_OPT","NEW_OPT","SHORT_OPT","LONG_OPT","LONG_OPT_VAL","LONG_OPT_WHAT","LONG_OPT_ARG","LONG_OPT_ARG_VAL"};
+
+
+ int8_t state = NEW_OPT;
+ struct opt_type *opt = NULL;
+ struct opt_type *opt_arg = NULL;
+ char* equalp = NULL;
+ char* pmn_s = NULL;
+ int8_t order = 0;
+ int32_t pb;
+ char argument[MAX_ARG_SIZE];
+ struct opt_parent *patch = NULL;
+
+ if ( cmd != OPT_CHECK && cmd != OPT_APPLY )
+ return FAILURE;
+
+ uint8_t del;
+
+ Load_config = load_cfg;
+ Testing = 0;
+
+
+ while ( s && strlen(s) >= 1 ) {
+
+ dbgf_all( DBGT_INFO, "cmd: %-10s, state: %s opt: %s, wordlen: %d rest: %s",
+ opt_cmd2str[cmd], state2str[state], opt?opt->long_name:"null",
wordlen(s), s );
+
+ if ( Testing ) {
+ Testing = 0;
+ close_ctrl_node( CTRL_CLOSE_SUCCESS, cn );
+ return SUCCESS;
+ }
+
+
+ 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]!='-' ) {
+
+ s++;
+ state=SHORT_OPT;
+
+ } 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]!='/' ) {
+
+ state=LONG_OPT;
+
+ } else if ( state == SHORT_OPT && wordlen(s) >=1 ) {
+
+ if ( !(opt = get_option( NULL, YES, s )) )
+ goto apply_args_error;
+
+ if ( (order=respect_opt_order( cmd, order, opt->order, opt, Load_config,
OPT_SET_POST, cn )) < 0 )
+ goto apply_args_error;
+
+ if ( opt->opt_t == A_PS0 ) {
+
+ if ( (pb=check_apply_parent_option( ADD, cmd, 0/*save*/, opt, s, cn )) == FAILURE )
+ goto apply_args_error;
+
+
+ if ( pb ) {
+ s+=pb;
+ state = NEXT_OPT;
+ } else if ( wordlen(s+1) >= 1 ) {
+ s++;
+ state = SHORT_OPT;
+ } else if ( wordlen(s+1) == 0 ) {
+ s++;
+ state = NEXT_OPT;
+ } else {
+ goto apply_args_error;
+ }
+
+ } else if ( opt->opt_t == A_PS1 || opt->opt_t == A_PMN ) {
+
+ s++;
+
+ if ( wordlen(s) > 1 && s[0] == '=' )
+ s++;
+
+ if ( wordlen(s) == 0 && !(s = nextword(s)) )
+ goto apply_args_error;
+
+ state = LONG_OPT_VAL;
+ }
+
+
+ } else if ( state == LONG_OPT && wordlen(s) >= 1 ) {
+
+ opt = get_option( NULL, NO, s );
+
+ if ( opt ) {
+
+ if ( (order=respect_opt_order( cmd, order, opt->order, opt, Load_config,
OPT_SET_POST, cn )) < 0 )
+ goto apply_args_error;
+
+
+ if ( opt->opt_t == A_PS0 ) {
+
+ if ( (pb=check_apply_parent_option( ADD, cmd, 0/*save*/, opt, s, cn )) == FAILURE )
+ goto apply_args_error;
+
+ if ( pb )
+ s+=pb;
+ else
+ s+=wordlen(s);
+
+ state = NEXT_OPT;
+
+ } else if ( opt->opt_t == A_PS1 || opt->opt_t == A_PMN ) {
+
+ equalp=index( s, '=' );
+
+ if ( equalp && equalp < s+wordlen(s) ) {
+
+ s = equalp+1;
+
+ } else {
+
+ if ( (s=nextword(s)) == NULL )
+ goto apply_args_error;
+
+ }
+
+ state = LONG_OPT_VAL;
+
+ } else {
+ goto apply_args_error;
+ }
+
+ } else {
+
+ goto apply_args_error;
+ }
+
+
+ } else if ( state == LONG_OPT_VAL && wordlen(s) >=1 ) {
+
+ 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 )
+ goto apply_args_error;
+
+ s+=pb;
+ state = NEXT_OPT;
+
+ } else if ( opt->opt_t == A_PMN ) {
+
+ s = s + (del = ((s[0] == ARG_RESET_CHAR) ? 1 : 0));
+
+ patch = add_opt_parent( &Patch_opt );
+
+ if ( (pb=call_option( del, OPT_PATCH, 0/*save*/, opt, patch, s, cn )) == FAILURE )
+ goto apply_args_error;
+
+ pmn_s = s;
+ s+=pb;
+
+ state = LONG_OPT_WHAT;
+
+ } else {
+ goto apply_args_error;
+ }
+
+ } else if ( state == LONG_OPT_WHAT ) {
+
+ if ( opt->opt_t != A_PMN )
+ goto apply_args_error;
+
+ char* slashp = index( s, '/' );
+
+ if ( slashp && slashp == nextword(s) && patch->p_diff == DEL )
{
+
+ wordCopy( argument, slashp+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 );
+
+ goto apply_args_error;
+
+ } else if ( slashp && slashp == nextword(s) ) {
+
+ //nextword starts with slashp
+
+ s = slashp+1;
+ state = LONG_OPT_ARG;
+
+ } else {
+
+ if ( (call_option( ADD, OPT_ADJUST, 0/*save*/, opt, patch, pmn_s, cn )) == FAILURE )
+ 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 )
+ goto apply_args_error;
+
+ del_opt_parent( &Patch_opt, patch );
+ patch = NULL;
+ state = NEXT_OPT;
+ }
+
+
+ } else if ( state == LONG_OPT_ARG && wordlen(s) >=1 ) {
+
+ opt_arg = get_option( opt, NO, s );
+
+ if ( !opt_arg || opt_arg->opt_t != A_CS1 || opt_arg->order != opt->order
)
+ goto apply_args_error;
+
+ equalp=index( s, '=' );
+
+ if ( equalp && equalp < s+wordlen(s) ) {
+
+ s = equalp+1;
+
+ } else {
+
+ if ( (s=nextword(s))==NULL )
+ goto apply_args_error;
+ }
+
+ state = LONG_OPT_ARG_VAL;
+
+
+ } else if ( state == LONG_OPT_ARG_VAL && wordlen(s) >=1 ) {
+
+ s = s + (del = ((s[0] == ARG_RESET_CHAR) ? 1 : 0));
+
+ if ( (pb=call_option( del, OPT_PATCH, 0/*save*/, opt_arg, patch, s, cn )) == FAILURE
)
+ goto apply_args_error;
+
+ s+=pb;
+
+ state = LONG_OPT_WHAT;
+
+
+ } else {
+ goto apply_args_error;
+ }
+
+ continue;
+ }
+
+
+ if ( state != LONG_OPT_ARG && state != NEW_OPT && state != NEXT_OPT
)
+ goto apply_args_error;
+
+
+ dbgf_all( DBGT_INFO, "all opts and args succesfully called with %s",
opt_cmd2str[cmd] );
+
+ if ( (order=respect_opt_order( cmd, order, 99, NULL, Load_config, OPT_SET_POST, cn ))
< 0 )
+ goto apply_args_error;
+
+
+ return SUCCESS;
+
+apply_args_error:
+
+ if ( patch )
+ del_opt_parent( &Patch_opt, patch );
+
+ snprintf( argument, MIN( sizeof(argument), wordlen(s)+1 ), "%s", s );
+
+ //otherwise invalid sysntax identified only by apply_stream_opts is not printed;
+ dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument: %s", argument );
+
+ return FAILURE;
+
+}
+
+
+
+void apply_init_args( int argc, char *argv[] ) {
+
+ prog_name = argv[0];
+
+ get_init_string( argc, argv );
+
+ char *stream_opts = nextword( init_string );
+
+ struct ctrl_node *cn = create_ctrl_node( STDOUT_FILENO, NULL, (getuid() | getgid())/*are
we root*/ ? NO : YES );
+
+ if ( ( apply_stream_opts( stream_opts, OPT_CHECK, YES/*load cfg*/, cn ) == FAILURE )
||
+ ( apply_stream_opts( stream_opts, OPT_APPLY, YES/*load cfg*/, cn ) == FAILURE ) )
+ cleanup_all( CLEANUP_FAILURE );
+
+ 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 ) {
+
+ 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 );
+
+ }
+}
+
+
+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 : "") );
+
+
+ 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 ) {
+
+ 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 )
+ cleanup_all(CLEANUP_SUCCESS);
+
+
+ }
+
+ return SUCCESS;
+}
+
+
+
+static 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 ) {
+
+ debug_level = strtol( patch->p_val, NULL , 10);
+
+ activate_debug_system();
+
+ } else if ( cmd == OPT_POST && !on_the_fly ) {
+
+ activate_debug_system();
+
+ }
+
+ 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 ) {
+
+ if ( cmd == OPT_APPLY ) {
+
+ int ival = strtol( patch->p_val, NULL , 10);
+
+
+ if ( ival == DBGL_SYS ||
+ ival == DBGL_CHANGES ||
+ ival == DBGL_TEST ||
+ ival == DBGL_ALL )
+ {
+
+ remove_dbgl_node( cn );
+ 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 );
+
+ } 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, _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 );
+/*
+ } else if ( ival == DBGL_SERVICES ) {
+
+ check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_SERVICES ), 0,
cn );
+
+ } else if ( ival == DBGL_HNAS ) {
+
+ check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_HNAS ), 0, cn
);
+
+ } else if ( ival == DBGL_GATEWAYS ) {
+
+ check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_GATEWAYS ), 0,
cn );
+*/
+ } else if ( ival == DBGL_PROFILE ) {
+
+#if defined MEMORY_USAGE
+ debugMemory( cn );
+#endif
+ }
+ close_ctrl_node( CTRL_CLOSE_SUCCESS, cn );
+ }
+
+ 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 ) {
+
+ if ( cmd != OPT_APPLY )
+ return SUCCESS;
+
+ if ( !cn )
+ return FAILURE;
+
+
+ if ( !strcmp(opt->long_name, ARG_VERBOSE_HELP)) {
+
+ show_opts_help( NO, YES, cn );
+
+ } else if ( !strcmp(opt->long_name, ARG_HELP) ) {
+
+ show_opts_help( NO, NO, cn );
+
+ } else if ( !strcmp(opt->long_name, ARG_VERBOSE_EXP) ) {
+
+ show_opts_help( YES, YES, cn );
+
+ } else if ( !strcmp(opt->long_name, ARG_EXP) ) {
+
+ 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);
+
+ } else {
+
+ show_opts_help( NO, NO, cn );
+ }
+
+ if ( !on_the_fly )
+ 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 ) {
+
+ if ( cmd == OPT_APPLY )
+ close_ctrl_node( CTRL_CLOSE_SUCCESS, cn );
+
+ return SUCCESS;
+}
+
+
+
+static 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] = "";
+
+ if ( cmd == OPT_CHECK || cmd == OPT_APPLY ) {
+
+ if ( wordlen( patch->p_val )+1 >= MAX_PATH_SIZE || patch->p_val[0] !=
'/' )
+ return FAILURE;
+
+ snprintf( tmp_dir, wordlen(patch->p_val)+1, "%s", patch->p_val );
+
+ if ( check_dir( tmp_dir, YES/*create*/, YES/*writable*/ ) == FAILURE )
+ return FAILURE;
+
+ if ( cmd == OPT_APPLY ) {
+ strcpy( run_dir, tmp_dir );
+ }
+
+ } else if ( cmd == OPT_SET_POST && !on_the_fly ) {
+
+ if ( check_dir( run_dir, YES/*create*/, YES/*writable*/ ) == FAILURE )
+ return FAILURE;
+
+ }
+
+ return SUCCESS;
+}
+
+
+
+
+
+
+
+
+
+static struct opt_type control_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, "\nGeneral configuration options:"},
+
+ {ODI,0,ARG_HELP, 'h',0,A_PS0,A_USR,A_DYI,A_ARG,A_END, 0, 0, 0, 0,
opt_help,
+ 0, "summarize help"},
+
+ {ODI,0,ARG_VERBOSE_HELP, 'H',0,A_PS0,A_USR,A_DYI,A_ARG,A_END, 0, 0, 0, 0,
opt_help,
+ 0, "show help"},
+
+ {ODI,0,ARG_EXP, 'x',0,A_PS0,A_USR,A_DYI,A_ARG,A_END, 0, 0, 0, 0,
opt_help,
+ 0, "summarize advanced and experimental options"},
+
+ {ODI,0,ARG_VERBOSE_EXP, 'X',0,A_PS0,A_USR,A_DYI,A_ARG,A_END, 0, 0,
0, 0, opt_help,
+ 0, "show advanced and experimental 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)"},
+
+ {ODI,0,ARG_NO_FORK, 'd',0,A_PS1,A_ADM,A_INI,A_ARG,A_ANY, 0, DBGL_MIN,
DBGL_MAX, -1, opt_no_fork,
+ ARG_VALUE_FORM, "print debug information instead of forking to background\n"
},
+ {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"
+ " 3 : changes\n"
+ " 4 : verbose changes\n"
+ " 5 : profiling (depends on -DDEBUG_MALLOC -DMEMORY_USAGE
-DPROFILE_DATA)\n"
+ " 7 : services\n"
+ " 8 : details\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,
+ ARG_DIR_FORM, "set runtime DIR of pid, socket,... - default: " DEF_RUN_DIR
" (must be defined before --" ARG_CONNECT ")."},
+
+
+
+ {ODI,0,"loop_mode", 'l',3,A_PS0,A_ADM,A_INI,A_ARG,A_ANY, &loop_mode, 0,
1, 0, 0,
+ 0, "put client daemon in loop mode to periodically refresh debug
information"},
+
+#ifndef LESS_OPTIONS
+ {ODI,0,"loop_interval", 0,
3,A_PS1,A_ADM,A_INI,A_ARG,A_ANY, &loop_interval, MIN_LOOP_INTERVAL,MAX_LOOP_INTERVAL,DEF_LOOP_INTERVAL,0,
+ 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,
+ 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 ) {
+
+ int i;
+
+ char *d = getenv(BMX_ENV_DEBUG);
+ if ( d && strtol(d, NULL , 10) >= DBGL_MIN && strtol(d, NULL ,
10) <= DBGL_MAX )
+ debug_level = strtol(d, NULL , 10);
+
+ for ( i = DBGL_MIN; i <= DBGL_MAX; i++ )
+ LIST_INIT_HEAD( dbgl_clients[i], struct dbgl_node, list );
+
+ openlog( "bmx", LOG_PID, LOG_DAEMON );
+
+ memset( &Patch_opt, 0, sizeof( struct opt_type ) );
+
+ LIST_INIT_HEAD( Patch_opt.d.childs_type_list, struct opt_data, list);
+ LIST_INIT_HEAD( Patch_opt.d.parents_instance_list, struct opt_parent, list);
+
+ register_options_array( control_options, sizeof( control_options ) );
+
+}
+
+void cleanup_config( void ) {
+
+ del_opt_parent( &Patch_opt, NULL );
+
+ while( !LIST_EMPTY( &opt_list ) )
+ remove_option( (struct opt_type*)list_entry( (&opt_list)->next, struct opt_data,
list ) );
+
+ free_init_string();
+
+}
+
+
+
+void cleanup_control( void ) {
+
+ int8_t i;
+
+ debug_system_active = NO;
+ closelog();
+
+ if ( unix_sock )
+ close( unix_sock );
+
+ unix_sock = 0;
+
+ close_ctrl_node( CTRL_PURGE_ALL, 0 );
+
+ for ( i = DBGL_MIN; i <= DBGL_MAX; i++ ) {
+
+ while( !LIST_EMPTY( &dbgl_clients[i] ) )
+ remove_dbgl_node( (list_entry( (&dbgl_clients[i])->next, struct dbgl_node, list
))->cn );
+
+ }
+
+}
+
Added: trunk/bmx/control.h
===================================================================
--- trunk/bmx/control.h (rev 0)
+++ trunk/bmx/control.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ *
+ * 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 MIN_UPTIME 0
+#define MAX_UPTIME 2147383 /*(((TP32/1000)/2)-100) /1000 to talk about seconds and not
ms, /2 to not render scheduled events outdated, -100 to be save */
+#define DEF_UPTIME 0
+
+#define DBGT_NONE 0
+#define DBGT_INFO 1
+#define DBGT_WARN 2
+#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_CHANGES 3
+#define DBGL_ALL 4
+#define DBGL_PROFILE 5
+#define DBGL_UNUSED 6
+#define DBGL_SERVICES 7
+#define DBGL_DETAILS 8
+#define DBGL_HNAS 9
+#define DBGL_LINKS 10
+#define DBGL_TEST 11
+#define DBGL_MAX 11
+#define DBGL_INVALID 12
+
+
+extern int unix_sock;
+
+extern struct list_head ctrl_list;
+
+#define ARG_PEDANTIC_CMDCHECK "pedantic_cmd_check"
+
+
+extern int32_t Client_mode;
+
+
+#define CONNECTION_END_STR "$"
+#define CONNECTION_END_CHR '$'
+
+enum {
+ CTRL_CLOSE_ERROR,
+ CTRL_CLOSE_SUCCESS,
+ CTRL_CLOSE_STRAIGHT,
+ CTRL_CLOSE_DELAY,
+ CTRL_CLEANUP,
+ CTRL_PURGE_ALL
+};
+
+#define CTRL_CLOSING_TIMEOUT 5000
+
+
+struct ctrl_node
+{
+ struct list_node list;
+ int fd;
+ void (*cn_fd_handler) (struct ctrl_node *);
+ uint32_t closing_stamp;
+ uint8_t authorized;
+ int8_t dbgl;
+};
+
+extern struct list_head dbgl_clients[DBGL_MAX+1];
+
+struct dbgl_node
+{
+ struct list_node list;
+ struct ctrl_node *cn;
+};
+
+
+
+// muting does not help if a changing value like time or seqno occurs durig the first
DBG_HIST_TEXT_SIZE bytes
+#define DBG_HIST_TEXT_SIZE 80
+#define DBG_HIST_SIZE 20
+//#define DBG_HIST_EXPIRE 100000
+
+struct dbg_histogram {
+ uint32_t print_stamp;
+ int32_t expire;
+ uint16_t check_len;
+ uint16_t catched;
+ char text[ DBG_HIST_TEXT_SIZE ];
+};
+
+
+#ifndef TESTDEBUG
+
+#define DBG_HIST_NEW 0x00
+#define DBG_HIST_MUTING 0x01
+#define DBG_HIST_MUTED 0x02
+
+#ifdef NODEBUGALL
+#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__ );
+
+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, ... );
+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 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_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 );
+void handle_ctrl_node( struct ctrl_node *cn );
+void close_ctrl_node( uint8_t cmd, struct ctrl_node *cn );
+struct ctrl_node *create_ctrl_node( int fd, void (*cn_fd_handler) (struct ctrl_node *),
uint8_t authorized );
+
+
+
+
+#define REFERENCE_KEY_WORD "ref:"
+
+#define EOS_DELIMITER '#'
+
+#define MAX_UNIX_MSG_SIZE 2000
+
+extern struct list_head opt_list;
+
+
+/* opt_t types (Parent/Child, Single/Multiple, 0/1/N-arguments) */
+#define A_PS0 0x01
+#define A_PS1 0x02
+#define A_PMN 0x14
+#define A_CS1 0x22
+
+
+/* auth_t types */
+#define A_ADM 0x10
+#define A_USR 0x00
+
+/* dyn_t types: */
+// can only be used on-the-fly
+#define A_DYN 0x20
+// can never be used on-the-fly
+#define A_INI 0x40
+// can be used during init and on-the-fly
+#define A_DYI 0x60
+
+/* cfg_t types: */
+// can only be set as command-line argument. NOT shows as relevant parameter
+#define A_ARG 0x02
+// can be set in config file and as command-line argument. Shows as relevant parameter
+#define A_CFA 0x03
+
+/* pos_t types: */
+// must be given as first argument
+#define A_BEG 0x01 NOT IMPLEMENTED
+// may appera anywhere in command stream
+#define A_ANY 0x02
+// must appear as last argument
+#define A_END 0x03
+// may appera anywhere in command stream but consumes remaining arguments
+#define A_EAT 0x04
+// must appear as last argunent and cosumes remaining arguments
+#define A_ETE 0x05
+
+
+extern char *opt_cmd2str[];
+
+
+struct opt_child {
+
+ struct list_node list;
+
+ struct opt_type *c_opt; // key, pointing to related opt_type
+ struct opt_parent *parent_instance;
+
+ char *c_val;
+
+ uint8_t p_diff; //ADD, DEL, NOP
+
+ char *c_ref;
+};
+
+
+struct opt_parent {
+
+ struct list_node list;
+
+ struct list_head childs_instance_list;
+
+ char *p_val; //key
+
+ uint8_t p_diff; //ADD, DEL, NOP
+
+ char *p_ref;
+
+};
+
+#define ODI {{0},0,{0,0,0,0},{0,0,0,0}}
+
+struct opt_data {
+
+ struct list_node list;
+
+ struct opt_type *parent_opt; //REMOVE THIS and use casting instead !
+
+ struct list_head childs_type_list; //if this opt is a section type, then further
sub-opts types can be listed here
+
+ struct list_head parents_instance_list; //
+// uint16_t found_parents;
+
+};
+
+struct opt_type {
+
+ struct opt_data d; //MUST be first structure in opt_type to allow casting between struct
opt_data and struct opt_type
+
+// int8_t old_order; // enforces an order during the init process, (0==anytime????),
1..99: in this order. Might become removed
+
+ char *parent_name;
+ char *long_name;
+
+ char short_name;
+ int8_t order; // enforces an order during the init process, (0==anytime????), 1..99:
in this order. Might become removed
+
+ uint8_t opt_t;
+
+ uint8_t auth_t;
+ uint8_t dyn_t;
+ uint8_t cfg_t;
+ uint8_t pos_t;
+
+ // if != NULL call_option() will be initialize / reset(ARG_RESET) to idef
+ int32_t *ival;
+ // if imin != imax call_option() will test for validity
+ int32_t imin;
+ int32_t imax;
+ int32_t idef;
+
+ int32_t (*call_custom_option)( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct
opt_parent *patch, struct ctrl_node *cn );
+
+#define ARG_VALUE_FORM "<VAL>"
+#define ARG_FILE_FORM "<FILE>"
+#define ARG_DIR_FORM "<DIRECTORY>"
+#define ARG_PORT_FORM "<PORT>"
+#define ARG_ADDR_FORM "<ADDRESS>"
+#define ARG_PREFIX_FORM "<NETADDR>/<PREFIX-LENGTH>"
+#define ARG_NETW_FORM "<NETADDR>"
+#define ARG_MASK_FORM "<NETMASK>"
+
+ char *syntax;
+ char *help;
+
+};
+
+
+#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.
+ // for registration and unregistration the primitives OPT_REGISTER and OPT_UNREGISTER
are used
+ // for configuration the primitives OPT_PATCH, OPT_ADJUST, OPT_CHECK, OPT_APPLY,
OPT_SET_POST, OPT_POST are used
+
+
+ // called once for each option after registration
+ // Returns FAILURE or SUCCESS
+ OPT_REGISTER,
+
+
+ OPT_PATCH,
+ // opt values are configured by creating, extending, adjusting and finally testing and
applying a patch
+ // option handler usually dont care about the creation of the patch.
+ // they get a complete patch which includes
+ // the option type-value pair and optional child type-valued pairs.
+
+
+ OPT_ADJUST,
+ // patched type-values pairs can be adjusted to a unified format before being checked or
applied
+ // this has the following advantages:
+ // tracked and applied values are equal (different value notations can be adjusted to a
unified format)
+ // -> track knows about already configured values (even when given with different
notation)
+ // -> can prevent/warn reconfiguration of already configured values
+ // -> can reject resetting of non-configured values
+
+
+ OPT_CHECK,
+ // to test a given patch (type-value pair) !
+ // Returns FAILURE or n>=0 of processed bytes-1
+
+
+ OPT_APPLY,
+ // to apply a previously created and adjusted patch
+ // Returns FAILURE or n>=0 of processed bytes-1
+
+
+ OPT_SET_POST,
+ // called whenever any option is changed and
+ // called ordered for each option and before next higher-order option
+ // Returns FAILURE or SUCCESS
+
+
+ OPT_POST,
+ // called whenever any option is changed and
+ // called ordered for each option after all options were (re-)set
+ // Returns FAILURE or SUCCESS
+
+
+ OPT_UNREGISTER
+ // called once before an option is unregistered
+ // Returns FAILURE or SUCCESS
+
+};
+
+// evaluates global variable: "on_the_fly"
+// fd may be set (>0) or not (=0)
+// cmd==OPT_SET_POST / OPT_POST:
+// s MBZ, return value is SUCCESS or FAILURE
+int32_t call_option( uint8_t del, uint8_t cmd, uint8_t _save, struct opt_type *opt,
struct opt_parent *parent, 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 );
+
+struct opt_type *get_option( struct opt_type *parent_opt, uint8_t short_opt, char *s );
+
+
+
+void set_opt_child_val ( struct opt_child *c, char *val );
+struct opt_child * get_opt_child ( struct opt_type *opt, struct opt_parent *p );
+
+
+void del_opt_parent( struct opt_type *opt, struct opt_parent *parent );
+struct opt_parent * add_opt_parent( struct opt_type *opt );
+
+void set_opt_parent_val ( struct opt_parent *p, char *val );
+struct opt_parent * get_opt_parent_val ( struct opt_type *opt, char *val );
+void set_opt_parent_ref ( struct opt_parent *p, char *ref );
+struct opt_parent * get_opt_parent_ref ( struct opt_type *opt, char *ref );
+
+
+
+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 ) );
+
+int respect_opt_order( uint8_t test, int8_t last, int8_t next, struct opt_type *on,
uint8_t load_config, uint8_t cmd, struct ctrl_node *cn );
+
+int8_t apply_stream_opts( char *s, uint8_t dryrun, uint8_t load_cfg, struct ctrl_node *cn
);
+
+
+extern int (*load_config_cb) ( uint8_t test, struct opt_type *opt, struct ctrl_node *cn
);
+
+extern int (*save_config_cb) ( uint8_t del, struct opt_type *opt, char *parent, char
*val, struct ctrl_node *cn );
+
+extern int (*derive_config) ( char *reference, char *derivation, struct ctrl_node *cn );
+
+
+void register_option( struct opt_type *opt );
+//void remove_option( struct opt_type *opt );
+void register_options_array ( struct opt_type *fixed_options, int size );
+
+extern int32_t Load_config;
+
+
+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 );
+
+
+void apply_init_args ( int argc, char *argv[] );
+
+extern struct opt_type Patch_opt;
+
+
+void init_control( void );
+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 );
+
+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 );
Added: trunk/bmx/cyassl/config.h
===================================================================
--- trunk/bmx/cyassl/config.h (rev 0)
+++ trunk/bmx/cyassl/config.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,73 @@
+/* ctaocrypt/include/config.h. Generated from config.h.in by configure. */
+/* ctaocrypt/include/config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "cyassl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.4.0"
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
Added: trunk/bmx/cyassl/misc.c
===================================================================
--- trunk/bmx/cyassl/misc.c (rev 0)
+++ trunk/bmx/cyassl/misc.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,128 @@
+/* misc.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 "misc.h"
+
+/* inlining these functions is a huge speed increase and a small size decrease,
+ because the functions are smaller than function call setup/cleanup, e.g.,
+ md5 benchmark is twice as fast with inline. If you don't want it, then
+ define NO_INLINE and compile this file into cyassl, otherwise it's used as
+ a source header
+ */
+
+#ifdef NO_INLINE
+ #define STATIC
+#else
+ #define STATIC static
+#endif
+
+
+#ifdef INTEL_INTRINSICS
+
+ #include <stdlib.h> /* get intrinsic definitions */
+
+ #pragma intrinsic(_lrotl, _lrotr)
+
+ STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+ {
+ return y ? _lrotl(x, y) : x;
+ }
+
+ STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+ {
+ return y ? _lrotr(x, y) : x;
+ }
+
+#else /* generic */
+
+ STATIC INLINE word32 rotlFixed(word32 x, word32 y)
+ {
+ return (x << y) | (x >> (sizeof(y) * 8 - y));
+ }
+
+
+ STATIC INLINE word32 rotrFixed(word32 x, word32 y)
+ {
+ return (x >> y) | (x << (sizeof(y) * 8 - y));
+ }
+
+#endif
+
+
+STATIC INLINE word32 ByteReverseWord32(word32 value)
+{
+#ifdef PPC_INTRINSICS
+ /* PPC: load reverse indexed instruction */
+ return (word32)__lwbrx(&value,0);
+#elif defined(FAST_ROTATE)
+ /* 5 instructions with rotate instruction, 9 without */
+ return (rotrFixed(value, 8U) & 0xff00ff00) |
+ (rotlFixed(value, 8U) & 0x00ff00ff);
+#else
+ /* 6 instructions with rotate instruction, 8 without */
+ value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) <<
8);
+ return rotlFixed(value, 16U);
+#endif
+}
+
+
+STATIC INLINE void ByteReverseWords(word32* out, const word32* in,
+ word32 byteCount)
+{
+ word32 count = byteCount/sizeof(word32), i;
+
+ for (i = 0; i < count; i++)
+ out[i] = ByteReverseWord32(in[i]);
+
+}
+
+
+STATIC INLINE void ByteReverseBytes(byte* out, const byte* in, word32 byteCount)
+{
+ word32* op = (word32*)out;
+ const word32* ip = (const word32*)in;
+
+ ByteReverseWords(op, ip, byteCount);
+}
+
+
+STATIC INLINE void XorWords(word* r, const word* a, word32 n)
+{
+ word32 i;
+
+ for (i = 0; i < n; i++) r[i] ^= a[i];
+}
+
+
+STATIC INLINE void xorbuf(byte* buf, const byte* mask, word32 count)
+{
+ if (((size_t)buf | (size_t)mask | count) % WORD_SIZE == 0)
+ XorWords( (word*)buf, (const word*)mask, count / WORD_SIZE);
+ else {
+ word32 i;
+ for (i = 0; i < count; i++) buf[i] ^= mask[i];
+ }
+}
+
+
+#undef STATIC
+
Added: trunk/bmx/cyassl/misc.h
===================================================================
--- trunk/bmx/cyassl/misc.h (rev 0)
+++ trunk/bmx/cyassl/misc.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,56 @@
+/* misc.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_MISC_H
+#define CTAO_CRYPT_MISC_H
+
+
+#include "types.h"
+#include <string.h>
+
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+#ifdef NO_INLINE
+word32 rotlFixed(word32, word32);
+word32 rotrFixed(word32, word32);
+
+word32 ByteReverseWord32(word32);
+void ByteReverseWords(word32*, const word32*, word32);
+void ByteReverseBytes(byte*, const byte*, word32);
+
+void XorWords(word*, const word*, word32);
+void xorbuf(byte*, const byte*, word32);
+#endif /* NO_INLINE */
+
+
+#ifdef __cplusplus
+ } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_MISC_H */
+
Added: trunk/bmx/cyassl/sha.c
===================================================================
--- trunk/bmx/cyassl/sha.c (rev 0)
+++ trunk/bmx/cyassl/sha.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,208 @@
+/* sha.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 "sha.h"
+#ifdef NO_INLINE
+ #include "misc.h"
+#else
+ #include "misc.c"
+#endif
+#include <string.h>
+#include <assert.h>
+
+
+#ifndef min
+
+ static INLINE word32 min(word32 a, word32 b)
+ {
+ return a > b ? b : a;
+ }
+
+#endif /* min */
+
+
+void InitSha(Sha* sha)
+{
+ sha->digest[0] = 0x67452301L;
+ sha->digest[1] = 0xEFCDAB89L;
+ sha->digest[2] = 0x98BADCFEL;
+ sha->digest[3] = 0x10325476L;
+ sha->digest[4] = 0xC3D2E1F0L;
+
+ sha->buffLen = 0;
+ sha->loLen = 0;
+ sha->hiLen = 0;
+}
+
+
+#define f1(x,y,z) (z^(x &(y^z)))
+#define f2(x,y,z) (x^y^z)
+#define f3(x,y,z) ((x&y)|(z&(x|y)))
+#define f4(x,y,z) (x^y^z)
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+= f1(w,x,y) + W[i] + 0x5A827999+ \
+ rotlFixed(v,5); w = rotlFixed(w,30);
+#define R1(v,w,x,y,z,i) z+= f1(w,x,y) + W[i] + 0x5A827999+ \
+ rotlFixed(v,5); w = rotlFixed(w,30);
+#define R2(v,w,x,y,z,i) z+= f2(w,x,y) + W[i] + 0x6ED9EBA1+ \
+ rotlFixed(v,5); w = rotlFixed(w,30);
+#define R3(v,w,x,y,z,i) z+= f3(w,x,y) + W[i] + 0x8F1BBCDC+ \
+ rotlFixed(v,5); w = rotlFixed(w,30);
+#define R4(v,w,x,y,z,i) z+= f4(w,x,y) + W[i] + 0xCA62C1D6+ \
+ rotlFixed(v,5); w = rotlFixed(w,30);
+
+
+static void Transform(Sha* sha)
+{
+ word32 W[80], i;
+
+ /* Copy context->state[] to working vars */
+ word32 a = sha->digest[0];
+ word32 b = sha->digest[1];
+ word32 c = sha->digest[2];
+ word32 d = sha->digest[3];
+ word32 e = sha->digest[4];
+
+ for (i = 0; i < 16; i++)
+ W[i] = sha->buffer[i];
+
+ for (i = 16; i < 80; i++)
+ W[i] = rotlFixed(W[i-3]^W[i-8]^W[i-14]^W[i-16],1);
+
+ /* 4 rounds of 20 operations each. */
+ for (i = 0; i < 20; ) {
+ R0(a,b,c,d,e,i); i++;
+ R0(e,a,b,c,d,i); i++;
+ R0(d,e,a,b,c,i); i++;
+ R0(c,d,e,a,b,i); i++;
+ R0(b,c,d,e,a,i); i++;
+ }
+
+ for (i = 20; i < 40; ) {
+ R2(a,b,c,d,e,i); i++;
+ R2(e,a,b,c,d,i); i++;
+ R2(d,e,a,b,c,i); i++;
+ R2(c,d,e,a,b,i); i++;
+ R2(b,c,d,e,a,i); i++;
+ }
+
+ for (i = 40; i < 60; ) {
+ R3(a,b,c,d,e,i); i++;
+ R3(e,a,b,c,d,i); i++;
+ R3(d,e,a,b,c,i); i++;
+ R3(c,d,e,a,b,i); i++;
+ R3(b,c,d,e,a,i); i++;
+ }
+
+ for (i = 60; i < 80; ) {
+ R4(a,b,c,d,e,i); i++;
+ R4(e,a,b,c,d,i); i++;
+ R4(d,e,a,b,c,i); i++;
+ R4(c,d,e,a,b,i); i++;
+ R4(b,c,d,e,a,i); i++;
+ }
+
+ /* Add the working vars back into digest state[] */
+ sha->digest[0] += a;
+ sha->digest[1] += b;
+ sha->digest[2] += c;
+ sha->digest[3] += d;
+ sha->digest[4] += e;
+}
+
+
+static INLINE void AddLength(Sha* sha, word32 len)
+{
+ word32 tmp = sha->loLen;
+ if ( (sha->loLen += len) < tmp)
+ sha->hiLen++; /* carry low to high */
+}
+
+
+void ShaUpdate(Sha* sha, const byte* data, word32 len)
+{
+ /* do block size increments */
+ byte* local = (byte*)sha->buffer;
+
+ while (len) {
+ word32 add = min(len, SHA_BLOCK_SIZE - sha->buffLen);
+ memcpy(&local[sha->buffLen], data, add);
+
+ sha->buffLen += add;
+ data += add;
+ len -= add;
+
+ if (sha->buffLen == SHA_BLOCK_SIZE) {
+ #ifdef LITTLE_ENDIAN_ORDER
+ ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+ #endif
+ Transform(sha);
+ AddLength(sha, SHA_BLOCK_SIZE);
+ sha->buffLen = 0;
+ }
+ }
+}
+
+
+void ShaFinal(Sha* sha, byte* hash)
+{
+ byte* local = (byte*)sha->buffer;
+
+ AddLength(sha, sha->buffLen); /* before adding pads */
+
+ local[sha->buffLen++] = 0x80; /* add 1 */
+
+ /* pad with zeros */
+ if (sha->buffLen > SHA_PAD_SIZE) {
+ memset(&local[sha->buffLen], 0, SHA_BLOCK_SIZE - sha->buffLen);
+ sha->buffLen += SHA_BLOCK_SIZE - sha->buffLen;
+
+ #ifdef LITTLE_ENDIAN_ORDER
+ ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+ #endif
+ Transform(sha);
+ sha->buffLen = 0;
+ }
+ memset(&local[sha->buffLen], 0, SHA_PAD_SIZE - sha->buffLen);
+
+ /* put lengths in bits */
+ sha->loLen = sha->loLen << 3;
+ sha->hiLen = (sha->loLen >> (8*sizeof(sha->loLen) - 3)) +
+ (sha->hiLen << 3);
+
+ /* store lengths */
+ #ifdef LITTLE_ENDIAN_ORDER
+ ByteReverseBytes(local, local, SHA_BLOCK_SIZE);
+ #endif
+ memcpy(&local[SHA_PAD_SIZE], &sha->hiLen, sizeof(word32));
+ memcpy(&local[SHA_PAD_SIZE + sizeof(word32)], &sha->loLen,
sizeof(word32));
+
+ Transform(sha);
+ #ifdef LITTLE_ENDIAN_ORDER
+ ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE);
+ #endif
+ memcpy(hash, sha->digest, SHA_DIGEST_SIZE);
+
+ InitSha(sha); /* reset state */
+}
+
Added: trunk/bmx/cyassl/sha.h
===================================================================
--- trunk/bmx/cyassl/sha.h (rev 0)
+++ trunk/bmx/cyassl/sha.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,62 @@
+/* sha.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_SHA_H
+#define CTAO_CRYPT_SHA_H
+
+#include "types.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+
+/* in bytes */
+enum {
+ SHA_BLOCK_SIZE = 64,
+ SHA_DIGEST_SIZE = 20,
+ SHA_PAD_SIZE = 56
+};
+
+
+/* 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;
+
+
+void InitSha(Sha*);
+void ShaUpdate(Sha*, const byte*, word32);
+void ShaFinal(Sha*, byte*);
+
+
+#ifdef __cplusplus
+ } /* extern "C" */
+#endif
+
+#endif /* CTAO_CRYPT_SHA_H */
+
Added: trunk/bmx/cyassl/types.h
===================================================================
--- trunk/bmx/cyassl/types.h (rev 0)
+++ trunk/bmx/cyassl/types.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,153 @@
+/* types.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_TYPES_H
+#define CTAO_CRYPT_TYPES_H
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#ifdef XMALLOC_USER
+ #include <stdlib.h> /* for size_t */
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+#if defined(WORDS_BIGENDIAN) || (defined(__MWERKS__) && !defined(__INTEL__))
+ #define BIG_ENDIAN_ORDER
+#endif
+
+#ifndef BIG_ENDIAN_ORDER
+ #define LITTLE_ENDIAN_ORDER
+#endif
+
+#ifdef IPHONE
+ #define SIZEOF_LONG_LONG 8
+#endif
+
+#ifdef THREADX
+ #define SIZEOF_LONG_LONG 8
+#endif
+
+
+typedef unsigned char byte;
+typedef unsigned short word16;
+typedef unsigned int word32;
+
+#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+ #define WORD64_AVAILABLE
+ #define WORD64_IS_DISTINCT_TYPE
+ typedef unsigned __int64 word64;
+#elif SIZEOF_LONG == 8
+ #define WORD64_AVAILABLE
+ typedef unsigned long word64;
+#elif SIZEOF_LONG_LONG == 8
+ #define WORD64_AVAILABLE
+ #define WORD64_IS_DISTINCT_TYPE
+ typedef unsigned long long word64;
+#else
+ #define MP_16BIT /* for mp_int, mp_word needs to be twice as big as
+ mp_digit, no 64 bit type so make mp_digit 16 bit */
+#endif
+
+
+/* These platforms have 64-bit CPU registers. */
+#if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \
+ defined(__mips64) || defined(__x86_64__))
+ typedef word32 hword;
+ typedef word64 word;
+#else
+ typedef word16 hword;
+ typedef word32 word;
+ #ifdef WORD64_AVAILABLE
+ typedef word64 dword;
+ #endif
+#endif
+
+
+enum {
+ WORD_SIZE = sizeof(word),
+ BIT_SIZE = 8,
+ WORD_BITS = WORD_SIZE * BIT_SIZE
+};
+
+
+/* use inlining if compiler allows */
+#ifndef NO_INLINE
+ #ifdef _MSC_VER
+ #define INLINE __inline
+ #elif __GNUC__
+ #define INLINE inline
+ #elif THREADX
+ #define INLINE _Inline
+ #else
+ #define INLINE
+ #endif
+#else
+ #define INLINE
+#endif
+
+
+/* set up rotate style */
+#if defined(_MSC_VER) || defined(__BCPLUSPLUS__)
+ #define INTEL_INTRINSICS
+ #define FAST_ROTATE
+#elif defined(__MWERKS__) && TARGET_CPU_PPC
+ #define PPC_INTRINSICS
+ #define FAST_ROTATE
+#elif defined(__GNUC__) && defined(__i386__)
+ /* GCC does peephole optimizations which should result in using rotate
+ instructions */
+ #define FAST_ROTATE
+#endif
+
+
+/* idea to add global alloc override by Moisés Guimarães */
+/* default to libc stuff */
+/* XCALLOC not used by CyaSSL or either math lib */
+/* XREALLOC is used once in mormal math lib, not in fast math lib */
+/* XFREE on some embeded systems doesn't like free(0) so test */
+#ifndef XMALLOC_USER
+ #define XMALLOC(s, h) malloc(s)
+ #define XFREE(p, h) if (p) free(p)
+ #define XREALLOC(p, n, h) realloc(p, n)
+ #define XCALLOC(n, s, h) calloc(n, s)
+#else
+ /* prototypes for our heap functions */
+ extern void *XMALLOC(size_t n, void* heap);
+ extern void *XREALLOC(void *p, size_t n, void* heap);
+ extern void *XCALLOC(size_t n, size_t s, void* heap);
+ extern void XFREE(void *p, void* heap);
+#endif
+
+
+#ifdef __cplusplus
+ } /* extern "C" */
+#endif
+
+
+#endif /* CTAO_CRYPT_TYPES_H */
+
Added: trunk/bmx/hna.c
===================================================================
--- trunk/bmx/hna.c (rev 0)
+++ trunk/bmx/hna.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,445 @@
+/*
+ * 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.
+ *
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+
+
+#include "bmx.h"
+#include "msg.h"
+#include "plugin.h"
+#include "hna.h"
+#include "route.h"
+
+AVL_TREE(global_uhna_tree, struct uhna4_node, key );
+AVL_TREE(local_uhna_tree, struct uhna4_node, key );
+
+/*
+struct uhna4_node *get_global_uhna_node(struct uhna4_key* key)
+{
+ return avl_find_item(&global_uhna_tree, key);
+}
+*/
+
+
+void set_uhna4_key(struct uhna4_key *key, uint8_t prefix_len, IP4_T glip4, uint32_t
metric)
+{
+ memset( key, 0, sizeof(struct uhna4_key));
+ key->prefix_len = prefix_len;
+ key->glip4 = glip4;
+ key->metric_be = htonl(metric);
+
+}
+
+
+
+
+
+int create_description_tlv_ip4(uint8_t *data, uint16_t max_size)
+{
+ struct avl_node *it = NULL;
+ struct dev_node *dev = primary_if;
+ int item = 0;
+ struct description0_msg_ip4 *glip4 = (struct description0_msg_ip4*) data;
+
+ do {
+ if (item == 0 || (dev != primary_if && dev->announce)) {
+
+ if ((item+1) * sizeof (struct description0_msg_ip4) >
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;
+ }
+
+ glip4[item++].ip4 = dev->ip4_addr;
+ }
+
+ } while ((dev = avl_iterate_item(&dev_ip4_tree, &it)));
+
+ 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;
+
+ 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 (item * sizeof (struct description0_msg_hna4) > max_size) {
+
+ 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;
+ }
+
+ uhna4[item].ip4 = un->key.glip4;
+ uhna4[item].metric = un->key.metric_be;
+ uhna4[item].prefix_len = un->key.prefix_len;
+ item++;
+ }
+
+ return item * sizeof (struct description0_msg_hna4);
+}
+
+
+
+int process_description_tlv_hna4(struct orig_node *on, struct frame_header *tlv, IDM_T
op, struct ctrl_node *cn )
+{
+ struct description0_msg_ip4 *glip4 = NULL;
+ struct description0_msg_hna4 *uhna4 = NULL;
+
+ assertion(-500357, (tlv->type == BMX_DSC_TLV_GLIP4 || tlv->type ==
BMX_DSC_TLV_UHNA4));
+
+ uint16_t msgs_size = ntohs(tlv->length) - sizeof (struct frame_header);
+ uint16_t msg_size, m, msgs;
+
+ 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);
+ }
+
+ msgs = msgs_size / msg_size;
+
+ for (m = 0; m < msgs; m++) {
+ struct uhna4_key key;
+
+ 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));
+ }
+
+ dbgf(DBGL_CHANGES, 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));
+
+ 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);
+ }
+
+ } else if (op == TLV_TEST) {
+
+ if (avl_find(&global_uhna_tree, &key))
+ return TLVS_BLOCKED;
+
+ } 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);
+
+ if (m == 0 && glip4) {
+ on->primary_ip4 = key.glip4;
+ addr_to_str(on->primary_ip4, on->primary_ip4_str);
+ }
+
+ } else if ( op == TLV_DEBUG ) {
+
+ dbg_printf(cn, " %s %s/%d metric %d\n", glip4 ?
"glip4:" : "uhna4:",
+ ipStr(key.glip4), key.prefix_len, ntohl(key.metric_be)
);
+
+ } else {
+ assertion( -500369, (NO));
+ }
+ }
+
+ return TLVS_SUCCESS;
+}
+
+
+
+
+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 );
+
+ paranoia( -500236, ((del && !un) || (!del && un)) );
+
+ // update uhna_tree:
+ if ( del ) {
+
+ paranoia(-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)
+ avl_remove(&local_uhna_tree, &un->key, -300213);
+
+ } else {
+
+ un = debugMalloc( sizeof (struct uhna4_node), -300090 );
+ un->key = *key;
+ un->on = on;
+ avl_insert(&global_uhna_tree, un, -300149);
+
+ if (!on)
+ 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)));
+
+ 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);
+ }
+
+ } else {
+ // update my description:
+ update_my_description_adv();
+
+ // 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);
+ }
+
+
+ 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 ) {
+
+ uint32_t ip;
+ int32_t mask;
+ uint32_t metric = 0;
+ struct uhna4_key key;
+
+ char new[30];
+
+ 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",
+ patch->p_diff, opt_cmd2str[cmd], _save, opt->long_name,
patch->p_val);
+
+
+ if ( patch->p_val[0] >= '0' && patch->p_val[0] <=
'9' ) {
+
+ // 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);
+
+ if ( str2netw( patch->p_val, &ip, '/', cn, &mask, 32 ) == FAILURE
)
+ return FAILURE;
+
+ 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 {
+
+ // the named UHNA
+
+ if ( adj_patched_network( opt, patch, new, &ip, &mask, cn ) == FAILURE )
+ return FAILURE;
+
+ if ( cmd == OPT_ADJUST )
+ return SUCCESS;
+
+ if ( patch->p_diff == NOP ) {
+
+ // change network and netmask parameters of an already configured and named HNA
+
+ char old[30];
+
+ // 1. check if announcing the new HNA would not block,
+ 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 )
+ 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);
+
+
+ }
+
+ // then continue with the new HNA
+ if ( str2netw( new , &ip, '/', cn, &mask, 32 ) == FAILURE )
+ return FAILURE;
+ }
+
+ set_uhna4_key(&key, mask, ip, metric);
+
+ struct uhna4_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"));
+
+ return FAILURE;
+ }
+
+ if ( cmd == OPT_APPLY )
+ configure_hna((patch->p_diff == DEL ? DEL : ADD), &key,
NULL);
+
+
+
+ } else if ( cmd == OPT_UNREGISTER ) {
+
+ struct avl_node *an;
+
+ while ((an = global_uhna_tree.root))
+ configure_hna(DEL, (struct uhna4_key*) AVL_NODE_KEY(
&global_uhna_tree, an), NULL);
+
+ }
+
+ return SUCCESS;
+
+}
+
+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 ) {
+
+
+ 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;
+
+ while ((un = (struct uhna4_node*) ((an =
avl_iterate(&global_uhna_tree, an)) ? an->item : NULL))) {
+
+ paranoia(-500361, (un->on && !un->on->desc0));
+
+ 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 : "
");
+
+ process_description_tlvs(un->on, NULL, TLV_DEBUG, cn);
+ hna_count++;
+ }
+
+ dbg_printf( cn, "\n" );
+ }
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+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_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"},
+
+ {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"},
+
+
+ {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
+int32_t hna_init( void ) {
+
+ register_options_array( hna_options, sizeof( hna_options ) );
+
+ return SUCCESS;
+}
+
+
+
+struct plugin_v2 *hna_get_plugin_v2( void ) {
+
+ static struct plugin_v2 hna_plugin;
+ memset( &hna_plugin, 0, sizeof ( struct plugin_v2 ) );
+
+ 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.cb_cleanup = hna_cleanup;
+
+ return &hna_plugin;
+}
+
+
Added: trunk/bmx/hna.h
===================================================================
--- trunk/bmx/hna.h (rev 0)
+++ trunk/bmx/hna.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * 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 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;
+};
+
+struct uhna4_node {
+ struct uhna4_key key;
+ struct orig_node *on;
+};
+
+extern struct avl_tree global_uhna_tree;
+extern struct avl_tree local_uhna_tree;
+
+struct plugin_v2 *hna_get_plugin_v2( void );
+
+void set_uhna4_key(struct uhna4_key *key, uint8_t prefix_len, IP4_T glip4, uint32_t
metric);
+
+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 uhna4_node *get_global_uhna_node( struct uhna4_key* key );
+
Added: trunk/bmx/iid.c
===================================================================
--- trunk/bmx/iid.c (rev 0)
+++ trunk/bmx/iid.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ *
+ * 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 <string.h>
+#include <stdio.h>
+
+#include "bmx.h"
+#include "iid.h"
+
+struct iid_repos my_iid_repos = { 0,0,0,0,{NULL} };
+
+int8_t iid_extend_repos(struct iid_repos *rep)
+{
+ dbgf( DBGL_CHANGES, DBGT_INFO, "sizeof iid: %lu, 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));
+
+ if (rep->arr_size + IID_REPOS_SIZE_BLOCK >= IID_REPOS_SIZE_WARN) {
+
+ dbgf( DBGL_SYS, DBGT_WARN, "%d", rep->arr_size);
+
+ if (rep->arr_size + IID_REPOS_SIZE_BLOCK >= IID_REPOS_SIZE_MAX)
+ return FAILURE;
+ }
+
+ int field_size = (rep == &my_iid_repos) ? sizeof (IID_NODE_T*) : sizeof
(struct iid_ref);
+
+ if (rep->arr_size) {
+
+ rep->arr.u8 = debugRealloc(rep->arr.u8, (rep->arr_size +
IID_REPOS_SIZE_BLOCK) * field_size, -300035);
+
+ } else {
+
+ rep->arr.u8 = debugMalloc(IID_REPOS_SIZE_BLOCK * field_size,
-300085);
+ rep->tot_used = IID_RSVD_MAX+1;
+ rep->min_free = IID_RSVD_MAX+1;
+ rep->max_free = IID_RSVD_MAX+1;
+ }
+
+ memset(&(rep->arr.u8[rep->arr_size * field_size]), 0,
IID_REPOS_SIZE_BLOCK * field_size);
+
+ rep->arr_size += IID_REPOS_SIZE_BLOCK;
+
+ return SUCCESS;
+}
+
+
+void iid_purge_repos( struct iid_repos *rep )
+{
+
+ if (rep->arr.u8)
+ debugFree(rep->arr.u8, -300135);
+
+ memset(rep, 0, sizeof ( struct iid_repos));
+
+}
+
+void iid_free(struct iid_repos *rep, IID_T iid)
+{
+ int m = (rep == &my_iid_repos);
+
+ assertion(-500330, (iid > IID_RSVD_MAX));
+ assertion(-500228, (iid < rep->arr_size && iid <
rep->max_free && rep->tot_used > IID_RSVD_MAX));
+ assertion(-500229, ((m ? (rep->arr.node[iid] != NULL) :
(rep->arr.ref[iid].myIID4x) != 0)));
+
+ if (m) {
+ rep->arr.node[iid] = NULL;
+ } else {
+ rep->arr.ref[iid].myIID4x = 0;
+ rep->arr.ref[iid].referred_timestamp_sec = 0;
+ }
+
+ rep->min_free = MIN(rep->min_free, iid);
+
+ if (rep->max_free == iid + 1) {
+
+ IID_T i;
+
+ for (i = iid; i > IID_MIN_USED; i--) {
+
+ if (m ? (rep->arr.node[i - 1] != NULL) : (rep->arr.ref[i -
1].myIID4x) != 0)
+ break;
+ }
+
+ rep->max_free = i;
+ }
+
+ rep->tot_used--;
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "mine %d, iid %d tot_used %d, min_free %d
max_free %d",
+ m, iid, rep->tot_used, rep->min_free, rep->max_free);
+
+ if (rep->tot_used > 0 && rep->tot_used <= IID_MIN_USED) {
+
+ assertion(-500362, (rep->tot_used == IID_MIN_USED &&
rep->max_free == IID_MIN_USED && rep->min_free == IID_MIN_USED));
+
+ iid_purge_repos( rep );
+
+ }
+
+}
+
+
+
+IID_NODE_T* iid_get_node_by_myIID4x( IID_T myIID4x ) {
+
+ if ( my_iid_repos.max_free <= myIID4x )
+ return NULL;
+
+ IID_NODE_T *dhn = my_iid_repos.arr.node[myIID4x];
+
+ assertion(-500328, (!dhn || dhn->myIID4orig == myIID4x));
+
+ if (dhn) {
+
+ if (!dhn->on) {
+ dbgf(DBGL_CHANGES, DBGT_INFO, "myIID4x %d INVALIDATED %d sec
ago",
+ myIID4x, (bmx_time - dhn->referred_timestamp) /
1000);
+ }
+
+ dhn->referred_timestamp = bmx_time;
+ }
+
+
+ return dhn;
+}
+
+
+IID_NODE_T* iid_get_node_by_neighIID4x( IID_NEIGH_T *nn, IID_T neighIID4x )
+{
+
+ if (!nn || nn->neighIID4x_repos.max_free <= 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) <=
+ ((MIN_DHASH_TO - (MIN_DHASH_TO / DHASH_TO_TOLERANCE_FK)) / 1000))) {
+
+ ref->referred_timestamp_sec = bmx_time_sec;
+
+ return iid_get_node_by_myIID4x(ref->myIID4x);
+ }
+
+ return NULL;
+}
+
+
+
+int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T myIID4x)
+{
+ assertion(-500326, (neighIID4x > IID_RSVD_MAX));
+ assertion(-500327, (myIID4x > IID_RSVD_MAX));
+ assertion(-500384, (neigh_rep && neigh_rep != &my_iid_repos));
+
+ assertion(-500245, (my_iid_repos.max_free > myIID4x));
+
+ IID_NODE_T *dhn = my_iid_repos.arr.node[myIID4x];
+
+ assertion(-500485, (dhn && dhn->on));
+
+ dhn->referred_timestamp = bmx_time;
+
+ if (neigh_rep->max_free > neighIID4x) {
+
+ struct iid_ref *ref = &(neigh_rep->arr.ref[neighIID4x]);
+
+ if (ref->myIID4x > IID_RSVD_MAX) {
+
+ if (ref->myIID4x == myIID4x ||
+ (((uint16_t)(((uint16_t) bmx_time_sec) -
ref->referred_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;
+ 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);
+
+ return FAILURE;
+ }
+
+ assertion(-500242, (ref->myIID4x == IID_RSVD_UNUSED));
+ }
+
+
+ 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",
+ neighIID4x, myIID4x, neigh_rep->arr_size,
neigh_rep->tot_used );
+ }
+
+ iid_extend_repos(neigh_rep);
+ }
+
+ 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;
+
+ return SUCCESS;
+}
+
+void iid_free_neighIID4x_by_myIID4x( struct iid_repos *rep, IID_T myIID4x)
+{
+ assertion(-500282, (rep != &my_iid_repos));
+ assertion(-500328, (myIID4x > IID_RSVD_MAX));
+
+ IID_T p;
+
+ for (p = IID_RSVD_MAX + 1; p < rep->max_free &&
rep->arr.ref[p].myIID4x != myIID4x; p++);
+
+ if (p < rep->max_free && rep->arr.ref[p].myIID4x == myIID4x) {
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "removed stale rep->arr.sid[%d] =
%d", p, myIID4x);
+
+ 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(DBGL_CHANGES, 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;
+}
+
Added: trunk/bmx/iid.h
===================================================================
--- trunk/bmx/iid.h (rev 0)
+++ trunk/bmx/iid.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * 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 _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 2
+
+#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
+
+
+struct iid_ref {
+ IID_T myIID4x;
+ uint16_t referred_timestamp_sec;
+};
+
+struct iid_repos {
+ IID_T arr_size; // the number of allocated array fields
+ IID_T min_free; // the first unused array field from the beginning of the array (might
be outside of allocated space)
+ IID_T max_free; // the first unused array field after the last used field in the array
(might be outside of allocated space)
+ IID_T tot_used; // the total number of used fields in the array
+ union {
+ uint8_t *u8;
+ IID_NODE_T **node;
+ struct iid_ref *ref;
+ } arr;
+};
+
+extern struct iid_repos my_iid_repos;
+
+
+
+int8_t iid_extend_repos( struct iid_repos *rep );
+
+void iid_purge_repos( struct iid_repos *rep );
+
+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);
+
+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_myIID4x( IID_T myIID4x );
+
+#endif
Added: trunk/bmx/lib/Makefile
===================================================================
--- trunk/bmx/lib/Makefile (rev 0)
+++ trunk/bmx/lib/Makefile 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,11 @@
+
+CFLAGS +=
+LDFLAGS +=
+
+PLUGINS = $(shell find -maxdepth 1 -type d | grep -e '^./bmx_' | sort)
+
+%:
+ for d in $(PLUGINS); do $(MAKE) CORE_CFLAGS='$(CORE_CFLAGS)' -C $$d $@ || echo
compiling $$d failed; echo;echo; done
+ echo 2 flags: $(CFLAGS)
+
+
Added: trunk/bmx/lib/bmx_uci_config/Makefile
===================================================================
--- trunk/bmx/lib/bmx_uci_config/Makefile (rev 0)
+++ trunk/bmx/lib/bmx_uci_config/Makefile 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,39 @@
+
+CFLAGS += $(CORE_CFLAGS) -fpic -I../../
+LDFLAGS += -shared -luci
+#-Wl,-soname,bmx_config
+
+PLUGIN_NAME = bmx_uci_config
+
+SRC_C = uci_config.c
+SRC_H = uci_config.h
+OBJS= $(SRC_C:.c=.o)
+
+PLUGIN_FULLNAME = $(PLUGIN_NAME).so
+PLUGIN_SHORTNAME = $(PLUGIN_NAME).so
+
+LIBDIR = /usr/lib
+THISDIR = $(shell pwd )
+
+all: $(PLUGIN_FULLNAME) Makefile
+
+
+$(PLUGIN_FULLNAME): $(OBJS) Makefile
+ $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(OBJS) -o $(PLUGIN_FULLNAME)
+ ln -f -s $(THISDIR)/$(PLUGIN_FULLNAME) $(THISDIR)/../$(PLUGIN_FULLNAME)
+
+%.o: %.c %.h Makefile
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+
+clean:
+ rm -f *.o *.so.$(PLUGIN_VER)
+
+
+install: all
+ mkdir -p $(LIBDIR)
+ install -D -m 755 $(PLUGIN_FULLNAME) $(LIBDIR)/$(PLUGIN_FULLNAME); /sbin/ldconfig -n
$(LIBDIR)
+
+
+strip: all
+ strip $(PLUGIN_FULLNAME)
Added: trunk/bmx/lib/bmx_uci_config/uci_config.c
===================================================================
--- trunk/bmx/lib/bmx_uci_config/uci_config.c (rev 0)
+++ trunk/bmx/lib/bmx_uci_config/uci_config.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,923 @@
+/*
+ * 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.
+ *
+ * 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 <strings.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <uci.h>
+
+#include "../../bmx.h"
+#include "../../plugin.h"
+#include "uci_config.h"
+
+static char conf_path[MAX_PATH_SIZE] = "";
+static char *bmx_conf_name = NULL;
+
+static char *uci_err;
+
+static struct uci_context *bmx_ctx = NULL;
+static struct uci_ptr bmx_pptr;
+
+static struct uci_context *net_ctx = NULL;
+
+static struct opt_type tmp_conf_opt;
+
+
+static void signal_hup_handler( int32_t sig ) {
+
+ dbgf( DBGL_SYS, DBGT_INFO, "reloading config" );
+
+ struct ctrl_node *cn = create_ctrl_node( STDOUT_FILENO, NULL, YES/*we are root*/ );
+
+ if ( (apply_stream_opts( ARG_RELOAD_CONFIG, OPT_CHECK, NO/*no cfg by default*/, cn ) ==
FAILURE) ||
+ (apply_stream_opts( ARG_RELOAD_CONFIG, OPT_APPLY, NO/*no cfg by default*/, cn ) ==
FAILURE) )
+ {
+ close_ctrl_node( CTRL_CLOSE_STRAIGHT, cn );
+ dbg( DBGL_SYS, DBGT_ERR, "reloading config failed! FIX your config NOW!" );
+ return;
+ }
+
+ 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 );
+
+}
+
+
+
+STATIC_FUNC
+int8_t uci_reload_package( struct uci_context *ctx, struct uci_ptr *ptr, char* package )
{
+
+ uci_unload(ctx, ptr->p);
+
+ memset( ptr, 0, sizeof( struct uci_ptr ) );
+ ptr->package = package;
+
+ if ( uci_lookup_ptr( ctx, ptr, NULL, false) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf( DBGL_SYS, DBGT_ERR, "%s", uci_err );
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+struct uci_element *uci_lookup( struct uci_context *ctx, struct uci_ptr *ptr, char *name
) {
+
+ dbgf_all( DBGT_INFO, "%s", name );
+
+ if ( name )
+ memset( ptr, 0, sizeof( struct uci_ptr ) );
+
+ if ( uci_lookup_ptr( ctx, ptr, name, false) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf( DBGL_SYS, DBGT_ERR, "%s %s", name, uci_err );
+ return NULL;
+ }
+ struct uci_element *e = ptr->last;
+
+ if ( !( ptr->flags & UCI_LOOKUP_COMPLETE ) ) {
+ dbgf_all( DBGT_INFO, "%s %s %s %s is not configured",
+ name, ptr->package, ptr->section, ptr->option );
+ return NULL;
+ }
+
+ return e;
+}
+
+
+
+STATIC_FUNC
+int uci_save_option( struct uci_context *ctx, char *conf_name, char *sect_name, char
*opt_name, char *opt_val, struct ctrl_node *cn ) {
+
+ dbgf_cn( cn, DBGL_CHANGES, DBGT_INFO, "%s.%s.%s=%s",
+ conf_name, sect_name, opt_name, opt_val );
+
+ struct uci_ptr ptr;
+ memset(&ptr, 0, sizeof(ptr));
+ ptr.package = conf_name;
+ ptr.section = sect_name;
+
+ if ( uci_lookup_ptr( ctx, &ptr, NULL, false ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "uci_lookup_str( %s.%s ): %s",
+ conf_name, sect_name, uci_err );
+ return FAILURE;
+ }
+
+ ptr.option = opt_name;
+ ptr.value = opt_val;
+
+ if ( uci_set( ctx, &ptr ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "uci_set( %s.%s.%s=%s ): %s",
+ conf_name, sect_name, opt_name, opt_val, uci_err );
+ return FAILURE;
+ }
+
+ if ( uci_save( ctx, ptr.p ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "uci_save( %s.%s.%s=%s ): %s",
+ conf_name, sect_name, opt_name, opt_val, uci_err );
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+int uci_create_section( struct uci_context *ctx, char *conf_name, char *sect_name, char
*opt_name, struct ctrl_node *cn ) {
+
+
+ struct uci_ptr ptr;
+
+ memset(&ptr, 0, sizeof(ptr));
+ ptr.package = conf_name;
+
+ if ( wordlen( sect_name ) )
+ ptr.section = sect_name;
+
+
+ if ( uci_lookup_ptr( ctx, &ptr, NULL, false ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "%s %s uci_lookup_str(): %s",
+ conf_name, opt_name, uci_err );
+ return FAILURE;
+ }
+
+ if ( uci_add_section( ctx, ptr.p, opt_name, &ptr.s ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "%s %s uci_add_section(): %s",
+ conf_name, opt_name, uci_err );
+ return FAILURE;
+ }
+
+ /*
+ if ( uci_save( ctx, ptr.p ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_fd( fd, DBGL_SYS, DBGT_ERR, "uci_save(): %s", uci_err );
+ return FAILURE;
+ }
+ */
+
+ if ( !wordlen( sect_name ) )
+ strcpy( sect_name, ptr.s->e.name );
+
+ dbgf_cn( cn, DBGL_CHANGES, DBGT_INFO, "%s.%s=%s",
+ conf_name, ptr.s->e.name, opt_name );
+
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+int uci_remove( struct uci_context *ctx, char *conf_name, char *sect_name, char
*opt_name, struct ctrl_node *cn ) {
+
+ dbgf_cn( cn, DBGL_CHANGES, DBGT_INFO, "%s.%s %s", conf_name, sect_name,
opt_name );
+
+ struct uci_ptr ptr;
+
+ memset(&ptr, 0, sizeof(ptr));
+ ptr.package = conf_name;
+ ptr.section = sect_name;
+
+ if ( uci_lookup_ptr( ctx, &ptr, NULL, false ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "uci_lookup_str(): %s", uci_err );
+ return FAILURE;
+ }
+
+ ptr.option = opt_name;
+
+ if ( uci_delete( ctx, &ptr ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "uci_delete(): %s", uci_err );
+ return FAILURE;
+ }
+
+ if ( uci_save( ctx, ptr.p ) != SUCCESS ) {
+ uci_get_errorstr( ctx, &uci_err, "" );
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "uci_save(): %s", uci_err );
+ return FAILURE;
+ }
+
+ // without doing this we get double free or corruption after config-reload or
uci_remove()
+ uci_reload_package( ctx, &bmx_pptr, conf_name );
+
+ return SUCCESS;
+
+}
+
+
+
+STATIC_FUNC
+int uci_get_sect_name( uint8_t create, struct ctrl_node *cn, struct uci_context *ctx,
+ char *conf_name, char *sect_name, char *sect_type, char
*opt_name, char *opt_val )
+{
+
+ struct uci_element *e;
+ struct uci_element *se;
+ int found=0;
+ struct uci_ptr ptr;
+
+ dbgf_all( DBGT_INFO, "%s %s %s.*.%s==%s",
+ create?"create":"get", sect_name, conf_name, opt_name, opt_val
);
+
+ paranoia( -500020, ( !conf_name || !sect_type || !sect_name ) );
+
+ uint8_t named_section = wordlen(sect_name) ? YES : NO;
+
+
+ if ( !(e=uci_lookup( ctx, &ptr, conf_name )) )
+ return FAILURE;
+
+ if ( e->type != UCI_TYPE_PACKAGE )
+ return FAILURE;
+
+
+ uci_foreach_element( &(ptr.p->sections), se) {
+
+ struct uci_section *s = uci_to_section(se);
+ struct uci_ptr sptr;
+ char name[MAX_ARG_SIZE];
+
+ if ( strcmp( sect_type, s->type ) )
+ continue;
+
+ if ( opt_name ) {
+
+ sprintf( name, "%s.%s.%s", conf_name, s->e.name, opt_name );
+
+ if ( !(e=uci_lookup( ctx, &sptr, name )) )
+ continue;
+
+ if ( opt_val && !wordsEqual( sptr.o->v.string, opt_val ) )
+ continue;
+
+ }
+
+ if ( !found && !named_section )
+ strcpy( sect_name, s->e.name );
+
+ else if ( wordsEqual( sect_name, s->e.name ) )
+ return SUCCESS;
+
+ found++;
+ }
+
+
+ if ( found == 0 && create ) {
+
+ if ( named_section && uci_save_option( ctx, conf_name, sect_name, NULL,
sect_type, cn ) != SUCCESS )
+ return FAILURE;
+
+ if ( !named_section && uci_create_section( ctx, conf_name, sect_name,
sect_type, cn ) != SUCCESS )
+ return FAILURE;
+
+ if ( opt_name && opt_val ) {
+
+ if ( uci_save_option( ctx, conf_name, sect_name, opt_name, opt_val, cn ) == SUCCESS )
+ return SUCCESS;
+
+ return FAILURE;
+
+ } else {
+
+ return SUCCESS;
+ }
+
+
+ return FAILURE;
+
+ } else if ( found == 1 ) {
+
+ return SUCCESS;
+
+ } else {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR,
+ "Found %d matching section with %s.*.%s==%s ! FIX your config NOW!",
+ found, conf_name, opt_name, opt_val );
+
+ return FAILURE;
+ }
+
+}
+
+
+STATIC_FUNC
+int bmx_derive_config ( char *reference, char *derivation, struct ctrl_node *cn ) {
+
+ struct uci_ptr sptr;
+ char name[MAX_ARG_SIZE];
+ struct uci_element *e;
+
+ wordCopy( name, reference + strlen( REFERENCE_KEY_WORD ) );
+
+ dbgf_all( DBGT_INFO, "going to lookup %s", name );
+
+ if ( !(e=uci_lookup( net_ctx, &sptr, name )) )
+ return FAILURE;
+
+ if ( sptr.o && wordlen( sptr.o->v.string ) && wordlen(
sptr.o->v.string ) < MAX_ARG_SIZE )
+ wordCopy( derivation, sptr.o->v.string );
+ else
+ return FAILURE;
+
+ uci_unload(net_ctx, sptr.p);
+
+ return SUCCESS;
+}
+
+
+STATIC_FUNC
+int bmx_save_config ( uint8_t del, struct opt_type *opt, char *p_val, char *c_val, struct
ctrl_node *cn ) {
+
+ dbgf( DBGL_CHANGES, DBGT_INFO, "%s p:%s c:%s", opt->long_name, p_val, c_val
);
+
+ char sect_name[MAX_ARG_SIZE]="";
+
+ paranoia( -500102, !opt );
+
+ if ( !bmx_ctx || !bmx_conf_name || opt->cfg_t == A_ARG )
+ return SUCCESS;
+
+ if ( opt->opt_t == A_PS1 ) {
+
+ // for all general options like ogm_interval, dad_timeout, ...
+
+ if ( del ) {
+
+ return uci_remove( bmx_ctx, bmx_conf_name, DEF_SECT_NAME, opt->long_name, cn );
+
+ } else {
+
+ uci_get_sect_name( YES/*create*/, cn, bmx_ctx, bmx_conf_name, DEF_SECT_NAME,
DEF_SECT_TYPE, NULL, NULL );
+ return uci_save_option( bmx_ctx, bmx_conf_name, DEF_SECT_NAME, opt->long_name,
c_val, cn );
+ }
+
+ } else if ( opt->opt_t == A_PMN ) {
+
+ // all A_PMN-options are saved as sections
+ // some with only one argument like HNAs, throw-rule, plugin, service
+ // section->options are processed in the following block
+
+ if ( uci_get_sect_name( ( del ? NO : YES/*create*/ ),
+ cn, bmx_ctx,
+ bmx_conf_name, sect_name, opt->long_name,
+ opt->long_name, p_val ) == FAILURE )
+ {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "unknown sect_name %s for %s %s",
+ sect_name, opt->long_name, p_val );
+
+ if ( del )
+ return SUCCESS;
+
+ return FAILURE;
+ }
+
+ if ( del )
+ return uci_remove( bmx_ctx, bmx_conf_name, sect_name, NULL, cn );
+
+ else
+ return uci_save_option( bmx_ctx, bmx_conf_name, sect_name, opt->long_name, c_val,
cn );
+
+
+ } else if ( opt->opt_t == A_CS1 && p_val ) {
+
+ // all A_CS1-child options like /ttl=20, /hide=1 from --dev eth0
+
+ if ( uci_get_sect_name( NO/*create*/, cn, bmx_ctx,
+ bmx_conf_name, sect_name, opt->d.parent_opt->long_name,
+ opt->d.parent_opt->long_name, p_val ) == FAILURE )
+ {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR,
+ "unknown A_1 sect_name %s sn %s %s on %s %s",
+ sect_name, opt->d.parent_opt->long_name, p_val, opt->long_name, c_val
);
+
+ if ( del )
+ return SUCCESS;
+
+ sect_name[0]=0;
+ if ( uci_get_sect_name( YES/*create*/, cn, bmx_ctx,
+ bmx_conf_name, sect_name, opt->d.parent_opt->long_name,
+ opt->d.parent_opt->long_name, p_val ) == FAILURE )
+ return FAILURE;
+
+ }
+
+ if ( del )
+ return uci_remove( bmx_ctx, bmx_conf_name, sect_name, opt->long_name, cn );
+
+ else
+ return uci_save_option( bmx_ctx, bmx_conf_name, sect_name, opt->long_name, c_val,
cn );
+
+
+ } else {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "%20s %20s -- %20s %s",
+ opt->d.parent_opt?opt->d.parent_opt->long_name:"--", p_val,
opt->long_name, c_val );
+
+ cleanup_all( -501004 );
+ }
+
+ return SUCCESS;
+}
+
+
+STATIC_FUNC
+int bmx_load_config ( uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn ) {
+
+ char name[MAX_PATH_SIZE]="";
+ struct uci_ptr sptr, optr;
+
+ if ( !bmx_ctx || !bmx_conf_name )
+ return SUCCESS;
+
+ if ( !opt->long_name || opt->cfg_t == A_ARG )
+ return SUCCESS;
+
+ paranoia( -500138, ( cmd != OPT_CHECK && cmd != OPT_APPLY ) );
+
+
+ if ( opt->opt_t == A_PS1 ) {
+
+ sprintf( name, "%s.%s.%s", bmx_conf_name, DEF_SECT_NAME, opt->long_name
);
+
+ dbgf_all( DBGT_INFO, "loading A_PS1-option: %s", name );
+
+ if ( !( uci_lookup( bmx_ctx, &optr, name ) ) ) {
+
+ if ( on_the_fly && //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,
+ "resetting A_PS1 %s.%s.%s to defaults failed",
+ bmx_conf_name, DEF_SECT_NAME, opt->long_name );
+
+ return FAILURE;
+ }
+
+ } else if ( !optr.o || !optr.o->v.string ) {
+
+ return FAILURE;
+
+ } else if ( check_apply_parent_option( ADD, cmd, NO/*save*/, opt, optr.o->v.string,
cn ) == FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "loading A_PS1 %s.%s.%s=%s failed",
+ bmx_conf_name, DEF_SECT_NAME, opt->long_name, optr.o->v.string );
+
+ return FAILURE;
+ }
+
+
+ } else if ( opt->opt_t == A_PMN ) {
+
+ // For A_M (multiple) and A_N (N-suboptons) we use a section)
+
+ dbgf_all( DBGT_INFO, "loading A_PMN-option: %s", opt->long_name );
+
+ struct uci_element *e;
+ struct uci_element *se;
+ struct opt_parent *p_tmp;
+
+ struct list_node *pos;
+
+ if ( !(e=uci_lookup( bmx_ctx, &sptr, bmx_conf_name )) )
+ return SUCCESS;
+
+ if ( e->type != UCI_TYPE_PACKAGE )
+ return SUCCESS;
+
+ // temporary cache all currently configured parents/sections
+ // so that we can later reset all of them which were not reloaded
+ del_opt_parent( &tmp_conf_opt, NULL );
+ list_for_each( pos, &(opt->d.parents_instance_list) ) {
+ p_tmp = list_entry( pos, struct opt_parent, list );
+
+ struct opt_parent *p_dup = add_opt_parent(&tmp_conf_opt);
+ set_opt_parent_val ( p_dup, p_tmp->p_val );
+ set_opt_parent_ref ( p_dup, p_tmp->p_ref );
+ }
+
+ uci_foreach_element( &(sptr.p->sections), se) {
+
+ struct uci_section *s = uci_to_section(se);
+
+ if ( strcmp( opt->long_name, s->type ) )
+ continue;
+
+ sprintf( name, "%s.%s.%s", bmx_conf_name, s->e.name, opt->long_name
);
+
+ dbgf_all( DBGT_INFO, "looking up: %s", name );
+
+
+ if ( !(e=uci_lookup( bmx_ctx, &optr, name )) ) {
+
+ if ( cmd == OPT_APPLY ) {
+ dbgf_cn( cn, DBGL_SYS, DBGT_WARN,
+ "looking up %s.%s.%s failed",
+ bmx_conf_name, s->e.name, opt->long_name );
+ }
+
+ continue;
+ }
+
+ char config_sect_val[MAX_ARG_SIZE];
+ strcpy( config_sect_val, optr.o->v.string );
+
+
+ struct opt_parent *patch = add_opt_parent( &Patch_opt );
+
+ if ( call_option( ADD, OPT_PATCH, NO/*save*/, opt, patch, config_sect_val, cn ) ==
FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "setting sect %s.%s.%s=%s failed",
+ bmx_conf_name, s->e.name, opt->long_name, config_sect_val );
+
+ del_opt_parent( &Patch_opt, patch );
+ return FAILURE;
+ }
+
+
+ list_for_each( pos, &opt->d.childs_type_list ) {
+
+ struct opt_type *opt_arg = (struct opt_type*)list_entry( pos, struct opt_data, list
);
+
+ sprintf( name, "%s.%s.%s", bmx_conf_name, s->e.name,
opt_arg->long_name );
+ dbgf_all( DBGT_INFO, "looking up: %s", name );
+
+ uint8_t del;
+ char config_sect_opt_val[MAX_ARG_SIZE];
+
+ if ( (e=uci_lookup( bmx_ctx, &optr, name )) ) {
+
+ strcpy( config_sect_opt_val, optr.o->v.string );
+ del = ADD;
+
+ } else {
+
+ if ( !on_the_fly )
+ continue; //no need to reset a configuration during init
+
+ config_sect_opt_val[0] = 0;
+ del = DEL;
+ }
+
+ if ( call_option( del, OPT_PATCH, NO/*save*/, opt_arg, patch, config_sect_opt_val, cn
) == FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR,
+ "setting opt %s %s %s.%s.%s=%s failed",
+ opt->long_name, config_sect_val,
+ bmx_conf_name, s->e.name, opt_arg->long_name, config_sect_opt_val );
+
+ del_opt_parent( &Patch_opt, patch );
+ return FAILURE;
+
+ } else {
+
+ dbgf_all( DBGT_INFO,
+ "patched opt %s %s %s.%s.%s=%s",
+ opt->long_name, config_sect_val,
+ bmx_conf_name, s->e.name, opt_arg->long_name, config_sect_opt_val );
+ }
+
+ }
+
+ if ( call_option( ADD, OPT_ADJUST, NO/*save*/, opt, patch, config_sect_val, cn ) ==
FAILURE ||
+ call_option( ADD, cmd, NO/*save*/, opt, patch, config_sect_val, cn ) ==
FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR,
+ "configuring section %s.%s=%s failed",
+ bmx_conf_name, s->e.name, opt->long_name );
+
+ del_opt_parent( &Patch_opt, patch );
+ return FAILURE;
+ }
+
+ // remove all (re)loaded opts from the cached list. They dont have to be resetted
later on
+ if ((p_tmp = get_opt_parent_ref(&tmp_conf_opt,
config_sect_val)) ||
+ (p_tmp = get_opt_parent_val(&tmp_conf_opt,
patch->p_val)))
+ del_opt_parent(&tmp_conf_opt, p_tmp);
+
+
+ del_opt_parent( &Patch_opt, patch );
+ }
+
+ // finally we have to reset all options which were configured previously but not
reloaded
+ list_for_each( pos, &tmp_conf_opt.d.parents_instance_list ) {
+
+ p_tmp = list_entry( pos, struct opt_parent, list );
+
+ if ( wordsEqual( p_tmp->p_val, BMX_LIB_UCI_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 );
+
+ } else if ( check_apply_parent_option( DEL, cmd, NO, opt, p_tmp->p_val, cn ) ==
FAILURE ) {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "calling %s %s failed", opt->long_name,
p_tmp->p_val );
+
+ return FAILURE;
+ }
+ }
+
+ } else {
+
+ dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "opt: %s illegal implementation! %s",
opt->long_name, ILLEGAL_STATE );
+
+ cleanup_all( -500137 );
+
+ }
+
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+int32_t opt_conf_reload ( 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 ) {
+
+ Load_config = 1;
+
+ if ( cmd == OPT_CHECK && bmx_ctx ) {
+
+ // without doing this we get double free or corruption after config-reload or
uci_remove()
+ uci_reload_package( bmx_ctx, &bmx_pptr, bmx_conf_name );
+ }
+ }
+
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+int32_t opt_conf_file ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct
opt_parent *patch, struct ctrl_node *cn ) {
+
+ char tmp_path[MAX_PATH_SIZE] = "";
+
+ if ( on_the_fly )
+ return SUCCESS;
+
+
+ if ( cmd == OPT_REGISTER ) {
+
+ sprintf( conf_path, "%s/%s", UCI_CONFDIR, DEF_CONF_NAME );
+ bmx_conf_name = strrchr( conf_path, '/') + 1;
+ *(strrchr( conf_path, '/'))=0;
+
+
+ } else if ( cmd == OPT_CHECK || cmd == OPT_APPLY ) {
+
+ if ( patch->p_diff == DEL )
+ return FAILURE;
+
+ char *f = patch->p_val;
+
+ if ( wordlen(f)+1 +strlen(UCI_CONFDIR)+1 >= MAX_PATH_SIZE )
+ return FAILURE;
+
+ if ( wordsEqual( f, ARG_NO_CONFIG_FILE ) ) {
+
+ if ( cmd == OPT_APPLY )
+ bmx_conf_name = NULL;
+
+ return SUCCESS;
+
+ } else if ( f[0] == '/' ) {
+
+ wordCopy( tmp_path, f );
+
+ char *tmp_name = strrchr( tmp_path, '/');
+
+ if ( !tmp_name || tmp_name == tmp_path ||
+ check_file( tmp_path, YES/*writable*/, NO/*executable*/ ) == FAILURE )
+ return FAILURE;
+
+ } else if ( strchr( f, '/') == NULL || strchr( f, '/') >=
f+wordlen(f) ) {
+
+ snprintf( tmp_path, strlen(UCI_CONFDIR)+1+wordlen(f)+1, "%s/%s",
UCI_CONFDIR, f );
+
+ if ( check_file( tmp_path, YES/*writable*/, NO/*executable*/ ) == FAILURE )
+ return FAILURE;
+
+
+ } else {
+
+ return FAILURE;
+ }
+
+ if ( cmd == OPT_APPLY ) {
+
+ strcpy( conf_path, tmp_path );
+ bmx_conf_name = strrchr( conf_path, '/') + 1;
+ *(strrchr( conf_path, '/'))=0;
+
+ }
+
+ return SUCCESS;
+
+
+ } else if ( cmd == OPT_SET_POST && bmx_conf_name ) {
+
+ sprintf( tmp_path, "%s/%s", conf_path, bmx_conf_name );
+
+ if ( check_file( tmp_path, YES/*writable*/, NO/*executable*/ ) == FAILURE )
+ return SUCCESS; //no config file used
+
+ bmx_ctx = uci_alloc_context();
+ 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 );
+
+ //initially lookup the bmx package so that we can save future changes
+ memset(&bmx_pptr, 0, sizeof(bmx_pptr));
+ bmx_pptr.package = bmx_conf_name;
+ uci_lookup_ptr( bmx_ctx, &bmx_pptr, NULL, false);
+
+ net_ctx = uci_alloc_context();
+ uci_set_confdir( net_ctx, conf_path );
+
+ load_config_cb = bmx_load_config;
+ save_config_cb = bmx_save_config;
+ derive_config = bmx_derive_config;
+
+ // we are already at OPT_SET_POST order>1 but
+ // we have nothing OPT_TESTed nor OPT_SET order=0 options, so load it now!
+ // order > 1 will be OPT_TEST and OPT_SET automatically via load_config_cb =
bmx_load_config function
+ struct list_node *list_pos;
+
+ int8_t test = 1;
+ while ( test >= 0 && test <= 1 ) {
+
+ list_for_each( list_pos, &opt_list ) {
+
+ struct opt_type *on = (struct opt_type*)list_entry( list_pos, struct opt_data, list
);
+
+ if ( (test && on->order != 1 ) || (!test && on->order == 0) )
{
+
+ if ( bmx_load_config( test?OPT_CHECK:OPT_APPLY, on, cn ) != SUCCESS ) {
+
+ dbgf_all( DBGT_ERR,
+ "bmx_load_config() %s %s failed",
+ test?"OPT_TEST":"OPT_SET",on->long_name );
+
+ return FAILURE;
+ }
+ }
+ }
+ test--;
+ }
+ }
+
+ signal( SIGHUP, signal_hup_handler );
+
+ return SUCCESS;
+}
+
+static uint8_t show_conf_general = YES;
+
+STATIC_FUNC
+int8_t show_conf ( struct ctrl_node *cn, void *data, struct opt_type *opt, struct
opt_parent *p, struct opt_child *c ) {
+
+ if ( show_conf_general && !c && opt->opt_t == A_PS1 ) {
+
+ dbg_printf( cn, "\toption '%s' '%s'\n", opt->long_name,
(p->p_ref ? p->p_ref : p->p_val) );
+
+ } else if ( !show_conf_general && !c && opt->opt_t == A_PMN ) {
+
+ dbg_printf( cn, "\nconfig '%s'\n", opt->long_name );
+ dbg_printf( cn, "\toption '%s' '%s'\n", opt->long_name,
(p->p_ref ? p->p_ref : p->p_val) );
+
+ } else if ( !show_conf_general && c && c->c_opt->opt_t ==
A_CS1 ) {
+
+ dbg_printf( cn, "\toption '%s' '%s'\n",
c->c_opt->long_name, (c->c_ref ? c->c_ref : c->c_val) );
+
+ }
+
+ return SUCCESS;
+}
+
+
+
+STATIC_FUNC
+int32_t opt_show_conf ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct
opt_parent *patch, struct ctrl_node *cn ) {
+
+ if ( cmd == OPT_APPLY ) {
+
+ dbg_printf( cn, "config '%s' '%s'\n", DEF_SECT_TYPE,
DEF_SECT_NAME );
+
+ show_conf_general = YES;
+ func_for_each_opt( cn, NULL, "show_conf()", show_conf );
+ show_conf_general = NO;
+ func_for_each_opt( cn, NULL, "show_conf()", show_conf );
+
+ dbg_printf( cn, "\n" );
+
+ }
+
+ return SUCCESS;
+}
+
+static struct opt_type config_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, "\nUCI config options:"},
+
+
+ {ODI,0,ARG_CONFIG_FILE, 'f',1,A_PS1,A_ADM,A_INI,A_ARG,A_ANY, 0, 0,
0, 0, opt_conf_file,
+ ARG_FILE_FORM, "use non-default config file. If defined, this must be the first
given option.\n"
+ " use --" ARG_CONFIG_FILE "="
ARG_NO_CONFIG_FILE " or -f" ARG_NO_CONFIG_FILE " to disable"},
+
+ {ODI,0,ARG_RELOAD_CONFIG, 0, 1,A_PS0,A_ADM,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0,
opt_conf_reload,
+ 0, "dynamically reload config file"},
+
+ {ODI,0,ARG_SHOW_CONFIG, 0, 5,A_PS0,A_ADM,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0,
opt_show_conf,
+ 0, "show current config as it could be saved to " ARG_CONFIG_FILE }
+};
+
+
+
+STATIC_FUNC
+void cleanup_conf( void ) {
+
+ del_opt_parent( &tmp_conf_opt, NULL );
+
+ load_config_cb = NULL;
+ save_config_cb = NULL;
+
+ if ( bmx_ctx )
+ uci_free_context( bmx_ctx );
+
+ if ( net_ctx )
+ uci_free_context( net_ctx );
+
+}
+
+STATIC_FUNC
+int32_t init_conf( void ) {
+
+ memset( &tmp_conf_opt, 0, sizeof( struct opt_type ) );
+ LIST_INIT_HEAD( tmp_conf_opt.d.childs_type_list, struct opt_data, list );
+ LIST_INIT_HEAD( tmp_conf_opt.d.parents_instance_list, struct opt_parent, list );
+
+ register_options_array( config_options, sizeof( config_options ) );
+
+ return SUCCESS;
+}
+
+
+
+struct plugin_v2* get_plugin_v2( void ) {
+
+ static struct plugin_v2 conf_plugin;
+
+ memset( &conf_plugin, 0, sizeof ( struct plugin_v2 ) );
+
+ 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.cb_init = init_conf;
+ conf_plugin.cb_cleanup = cleanup_conf;
+
+ return &conf_plugin;
+}
+
Added: trunk/bmx/lib/bmx_uci_config/uci_config.h
===================================================================
--- trunk/bmx/lib/bmx_uci_config/uci_config.h (rev 0)
+++ trunk/bmx/lib/bmx_uci_config/uci_config.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ *
+ * 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 DEF_CONF_NAME "bmx"
+#define DEF_SECT_NAME "general"
+#define DEF_SECT_TYPE "bmx"
+
+#define ARG_CONFIG_FILE "config_file"
+#define ARG_SAVE_CONFIG "save_config"
+#define ARG_SHOW_CONFIG "show_config"
+#define ARG_RELOAD_CONFIG "reload_config"
+
+#define ARG_NO_CONFIG_FILE "0"
\ No newline at end of file
Added: trunk/bmx/list.c
===================================================================
--- trunk/bmx/list.c (rev 0)
+++ trunk/bmx/list.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*
+ * This list implementation is originally based on the
+ * 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:
+ * - 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 "bmx.h"
+#include "list.h"
+
+/**
+ * list_iterate - return pointer to next node maintained in the list or NULL
+ * @head: list head of maintained nodes
+ * @node: a node maintained in the list or NULL
+ */
+void * list_iterate(struct list_head *head, void *node)
+{
+ struct list_node * ln;
+
+ if (head->prev == (ln = ((node ?
+ (struct list_node*) (((char*) node) + head->list_node_offset) :
+ (struct list_node*) head))->next)
+ )
+ return NULL;
+
+ return (((char*) ln) - head->list_node_offset);
+}
+
+
+
+/**
+ * list_add_head - add a new entry at the beginning of a list
+ * @head: list head to add it after
+ * @new: new entry to be added
+ */
+void list_add_head(struct list_head *head, struct list_node *new)
+{
+
+ new->next = head->next;
+ ((struct list_node *) head)->next = new;
+
+ if (head->prev == (struct list_node *) head)
+ head->prev = new;
+
+ head->items++;
+
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @head: list head to add it before
+ * @new: new entry to be added
+ */
+void list_add_tail(struct list_head *head, struct list_node *new )
+{
+ new->next = (struct list_node *) head;
+ head->prev->next = new;
+
+ head->prev = new;
+ head->items++;
+}
+
+
+void list_add_after(struct list_head *head, struct list_node *pos, struct list_node
*new)
+{
+ new->next = pos->next;
+ pos->next = new;
+ head->items++;
+}
+
+/**
+ * list_del_next - deletes next entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an
undefined state.
+ */
+void list_del_next(struct list_head *head, struct list_node *pos)
+{
+ struct list_node *entry = pos->next;
+
+ if (head->prev == entry)
+ head->prev = pos;
+
+ pos->next = entry->next;
+
+ head->items--;
+}
+
+void *list_rem_head(struct list_head *head)
+{
+ if (LIST_EMPTY(head))
+ return NULL;
+
+ struct list_node* entry = head->next;
+
+ list_del_next(head, (struct list_node*) head);
+
+ return ((char*) entry) -head->list_node_offset;
+}
+
+
+
+/**
+ * plist_get_next - return pointer to next node maintained in the list or NULL
+ * @head: list head of maintained nodes
+ * @@pnode: MBZ at beginning! pointing to current plist_node in list
+ */
+void * plist_iterate(struct list_head *head, struct plist_node **pln)
+{
+
+ if (head->prev == (struct list_node*)
+ (*pln = *pln ? (struct plist_node*) ((*pln)->list.next) : (struct
plist_node*) (head->next)))
+ return NULL;
+
+ 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;
+*/
+
+}
+
+
+
+static struct plist_node *plist_node_create(void *item)
+{
+ paranoia(-500266, (!item));
+ struct plist_node *plh = debugMalloc(sizeof ( struct plist_node), -300113);
+
+ plh->item = item;
+ return plh;
+}
+
+void plist_add_head(struct list_head *head, void *item)
+{
+ list_add_head(head, &((plist_node_create(item))->list));
+}
+
+void plist_add_tail(struct list_head *head, void *item)
+{
+ list_add_tail(head, &((plist_node_create(item))->list));
+}
+
+void * plist_rem_head(struct list_head *head)
+{
+ struct plist_node *pln = list_rem_head(head);
+
+ if ( !pln )
+ return NULL;
+
+ void *item = pln->item;
+
+ debugFree( pln, -300114 );
+
+ return item;
+}
Added: trunk/bmx/list.h
===================================================================
--- trunk/bmx/list.h (rev 0)
+++ trunk/bmx/list.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*
+ * This list implementation is originally based on the
+ * double-linked list implementaton from the linux-kernel
+ * which can be found in include/linux/list.h
+ *
+ * The following has been changed to better fit my needs and intuition:
+ * - 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!
+ */
+
+
+#ifndef _LIST_H
+#define _LIST_H
+
+
+
+struct list_node {
+ struct list_node *next;
+};
+
+struct list_head {
+ struct list_node *next, *prev;
+ uint16_t items;
+ uint16_t list_node_offset;
+};
+
+struct plist_node {
+ struct list_node list;
+ void *item;
+};
+
+
+#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 { \
+ ptr.next = ptr.prev =(struct list_node *)&ptr; \
+ ptr.items = 0; \
+ ptr.list_node_offset = ((unsigned long)(&((element_type
*)0)->list_node_field)); \
+} while (0)
+
+#define LIST_EMPTY(lst) ((lst)->next == (struct list_node *)(lst))
+
+
+#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_add_head(struct list_head *head, struct list_node *new);
+void list_add_tail(struct list_head *head, struct list_node *new );
+void list_add_after(struct list_head *head, struct list_node *pos, struct list_node
*new);
+void list_del_next(struct list_head *head, struct list_node *pos);
+void *list_rem_head(struct list_head *head);
+
+
+#define plist_get_first(head) (LIST_EMPTY(head) ? NULL : \
+ ((struct plist_node*)(((char*) (head)->next) -
(head)->list_node_offset))->item )
+
+#define plist_get_last(head) (LIST_EMPTY(head) ? NULL : \
+ ((struct plist_node*)(((char*) (head)->prev) -
(head)->list_node_offset))-item )
+
+void * plist_iterate(struct list_head *head, struct plist_node **pln);
+
+void plist_add_head(struct list_head *head, void *item);
+void plist_add_tail(struct list_head *head, void *item);
+void *plist_rem_head(struct list_head *head);
+
+
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) ( (type *)( (char *)(ptr) - (unsigned
long)(&((type *)0)->member) ) )
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (struct list_node *)(head); pos = pos->next)
+
+#define list_for_each_item(pos, head, item, type, member) \
+ for (pos = (head)->next; \
+ pos != (struct list_node *)(head) && \
+ (item = ((type *)( (char *)(pos) - (unsigned long)(&((type
*)0)->member) ) )); \
+ pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (struct list_node *)(head); \
+ pos = n, n = pos->next)
+
+
+#endif
Added: trunk/bmx/msg.c
===================================================================
--- trunk/bmx/msg.c (rev 0)
+++ trunk/bmx/msg.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,2291 @@
+/*
+ * 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.
+ *
+ * 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+
+//#include <sha.h>
+
+#include "bmx.h"
+#include "msg.h"
+#include "hna.h"
+#include "schedule.h"
+
+
+static Sha bmx_sha;
+
+AVL_TREE( description_cache_tree, struct description_cache_node, dhash );
+
+
+
+static int32_t max_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 */
+
+int32_t my_hello_interval = DEF_HELLO_INTERVAL;
+
+int32_t ogm_resend_attempts = DEF_OGM_RESEND_ATTEMPTS;
+
+int my_desc0_tlv_len = 0;
+
+IID_T myIID4me = IID_RSVD_UNUSED;
+
+
+LIST_SIMPEL( ogm_aggreg_list, struct ogm_aggreg_node, list );
+uint32_t ogm_aggreg_pending = 0;
+static SQN_T ogm_aggreg_sqn_max;
+
+
+char *tlv_op_str[] =
{"TLV_DEL","TLV_TEST","TLV_ADD","TLV_DONE","TLV_DEBUG"};
+
+
+
+
+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 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}
+
+};
+
+
+
+
+STATIC_FUNC
+struct description * rem_cached_description(struct description_hash *dhash)
+{
+ struct description_cache_node *dcn;
+
+ if (!(dcn = avl_find_item(&description_cache_tree, dhash)))
+ return NULL;
+
+ struct description *desc0 = dcn->description;
+
+ avl_remove(&description_cache_tree, &dcn->dhash, -300206);
+ debugFree(dcn, -300108);
+
+ return desc0;
+}
+
+STATIC_FUNC
+struct description_cache_node *purge_cached_descriptions( IDM_T purge_all ) {
+
+ struct description_cache_node *dcn;
+ struct description_cache_node *dcn_min = NULL;
+ struct description_hash tmp_dhash;
+ memset( &tmp_dhash, 0, sizeof(struct description_hash));
+
+ dbgf(DBGL_CHANGES, 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);
+
+ if (purge_all || ((uint32_t) (bmx_time - dcn->timestamp)) >
DEF_DESC0_CACHE_TO) {
+
+ avl_remove(&description_cache_tree, &dcn->dhash,
-300208);
+ debugFree(dcn->description, -300100);
+ debugFree(dcn, -300101);
+
+ } else {
+
+ if (!dcn_min || LESS_U32(dcn->timestamp,
dcn_min->timestamp))
+ dcn_min = dcn;
+ }
+ }
+
+ return dcn_min;
+}
+
+STATIC_FUNC
+void cache_description(struct description *desc, struct description_hash *dhash)
+{
+ struct description_cache_node *dcn;
+
+ uint16_t desc_len = sizeof (struct description) + ntohs(desc->dsc_tlvs_len);
+
+ if ((dcn = avl_find_item(&description_cache_tree, dhash))) {
+ dcn->timestamp = bmx_time;
+ return;
+ }
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%8X..", dhash->h.u32[0]);
+
+
+ paranoia(-500261, (description_cache_tree.items > DEF_DESC0_CACHE_SIZE));
+
+ if ( description_cache_tree.items == DEF_DESC0_CACHE_SIZE ) {
+
+
+ struct description_cache_node *dcn_min = purge_cached_descriptions( NO
);
+
+ dbgf(DBGL_SYS, DBGT_WARN, "desc0_cache_tree reached %d items!
cleaned up %d items!",
+ DEF_DESC0_CACHE_SIZE, DEF_DESC0_CACHE_SIZE -
description_cache_tree.items);
+
+ if (description_cache_tree.items == DEF_DESC0_CACHE_SIZE) {
+ avl_remove(&description_cache_tree, &dcn_min->dhash,
-300209);
+ debugFree(dcn_min->description, -300102);
+ debugFree(dcn_min, -300103);
+ }
+ }
+
+ paranoia(-500273, (desc_len != sizeof ( struct description) +
ntohs(desc->dsc_tlvs_len)));
+
+ 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 );
+ 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(DBGL_CHANGES, 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 )
+{
+ struct tx_timestamp_node *ttn = NULL;
+ struct tx_timestamp_key key;
+ struct dhash_node *dhn = NULL;
+
+ if (tx_task->myIID4x >= IID_MIN_USED && !((dhn =
iid_get_node_by_myIID4x(tx_task->myIID4x)) && dhn->on)) {
+ goto tx_timestamped_deny;
+ }
+
+ 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;
+
+ if (frame_handler[frame_type].min_tx_interval && (ttn =
avl_find_item(&dev->tx_timestamp_tree, &key))) {
+
+ if (((uint32_t) (bmx_time - ttn->timestamp) <
frame_handler[frame_type].min_tx_interval)) {
+
+ goto tx_timestamped_deny;
+ }
+
+ ttn->timestamp = bmx_time;
+ }
+
+ if (!ttn)
+ ttn = tx_timestamp_add(dev, &key);
+
+ return NO;
+
+
+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);
+
+ return YES;
+}
+
+
+
+
+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;
+ }
+
+ 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;
+ }
+
+ return SUCCESS;
+}
+
+
+
+
+
+IDM_T process_description_tlvs(struct orig_node *on, struct description *desc_new, IDM_T
op, struct ctrl_node *cn)
+{
+ 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;
+
+
+ dbgf(DBGL_CHANGES, 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));
+
+
+ size = ntohs(desc->dsc_tlvs_len);
+ tlv = NULL;
+ pos = t = pt = 0;
+
+
+ assertion(-500274, (size <= MAX_DESC0_TLV_SIZE)); // checked in
rx_frm_desc0_advs()
+
+ while (pos + sizeof ( struct frame_header) < size) {
+
+ tlv = (struct frame_header*) (((char*) desc) + sizeof (struct
description) + pos);
+ tlv_size = ntohs(tlv->length);
+
+ if ((t = tlv->type) < pt ||
+ tlv_size < sizeof ( struct frame_header) ||
+ tlv_size + pos > size) {
+
+ dbgf(DBGL_SYS, DBGT_ERR,
+ "illegal sizes %d for type %s",
tlv_size, description0_tlv_handler[t].name);
+ goto process_desc0_tlv_error;
+ }
+
+ 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;
+
+ } 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;
+
+ } else if (!(description0_tlv_handler[t].variable_msg_size)
&&
+ (tlv_size - sizeof (struct frame_header)) %
description0_tlv_handler[t].min_msg_size) {
+
+ dbgf(DBGL_SYS, DBGT_ERR,
+ "nonmaching size %d for type %s",
tlv_size, description0_tlv_handler[t].name);
+ goto process_desc0_tlv_error;
+
+ } else if ((tlv_result =
(*(description0_tlv_handler[t].process_tlv)) (on, tlv, op, cn)) != TLVS_SUCCESS) {
+
+ assertion(-500356, (op == TLV_TEST));
+
+ dbgf(DBGL_SYS, DBGT_ERR,
+ "%s size %d %s",
description0_tlv_handler[t].name, tlv_size,
+ tlv_result == TLVS_BLOCKED ? "BLOCKED"
: "FAILURE");
+
+ if (tlv_result == TLVS_BLOCKED) {
+
+ on->blocked = YES;
+
+ if (!avl_find(&blocked_tree,
&on->id))
+ avl_insert(&blocked_tree, on,
-300165);
+
+ return TLVS_BLOCKED;
+ }
+
+ goto process_desc0_tlv_msg_error;
+ }
+
+ pt = t;
+ pos += tlv_size;
+ }
+
+ if (pos != size) {
+ dbgf(DBGL_SYS, DBGT_ERR, "nonmaching tlvs pos %d != size
%d", pos, size );
+
+ goto process_desc0_tlv_error;
+ }
+
+ } while (++op < TLV_DONE);
+
+ if ( op == TLV_DONE ) {
+ on->blocked = NO;
+ avl_remove(&blocked_tree, &on->id, -300211);
+ }
+
+ return SUCCESS;
+
+
+process_desc0_tlv_msg_error:
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "rcvd problematic message");
+
+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)
+{
+ assertion(-500262, (pb && pb->ln && desc));
+ assertion(-500381, (!avl_find( &dhash_tree, dhash )));
+
+ struct dhash_node *dhn;
+ struct orig_node *on = NULL;
+ int id_name_len;
+
+
+ dbgf( DBGL_CHANGES, 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 ((on = avl_find_item(&orig_tree, &desc->id))) {
+
+ assertion(-500383, (on->dhn));
+
+ if (((uint32_t) (bmx_time - on->dhn->referred_timestamp)) <
(uint32_t) dad_to) {
+
+ if ( ((SQN_T)(ntohs(desc->dsc_sqn) - (on->desc0_sqn + 1)))
> SQN_DAD_RANGE ) {
+
+ dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert: new dsc_sqn %d
not > old %d + 1",
+ ntohs(desc->dsc_sqn), on->desc0_sqn);
+
+ goto process_desc0_ignore;
+ }
+
+ if (LESS_SQN(ntohs(desc->ogm_sqn_min), (on->ogm_sqn_min +
MAX_OGM0_SQN_RANGE))) {
+
+ 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);
+
+ goto process_desc0_ignore;
+ }
+ }
+
+
+ } 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(DBGL_CHANGES, 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 !!
+
+
+ on->updated_timestamp = bmx_time;
+ on->desc0_sqn = ntohs(desc->dsc_sqn);
+
+ 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;
+
+// on->ogm_sqn_mask = (MAX_SQN << on->ogm_sqn_pq_bits);
+// on->ogm_sqn_steps = (0x01 << on->ogm_sqn_pq_bits);
+
+
+ struct metric_algo test_algo;
+ memset(&test_algo, 0, sizeof (struct metric_algo));
+
+ 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;
+
+
+ if ( validate_metric_algo( &test_algo, NULL ) == FAILURE )
+ goto process_desc0_error;
+
+ memcpy(&on->path_metric_algo, &test_algo, sizeof (struct
metric_algo));
+
+ 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);
+
+
+ // 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 (on->desc0)
+ debugFree(on->desc0, -300111);
+
+ on->desc0 = desc;
+ desc = NULL;
+
+ struct neigh_node *dhn_neigh = NULL;
+
+ if (on->dhn) {
+ dhn_neigh = on->dhn->neigh;
+ on->dhn->neigh = NULL;
+ on->dhn->on = NULL;
+ invalidate_dhash_node(on->dhn);
+ }
+
+ on->dhn = dhn = create_dhash_node(dhash, on);
+
+ if ( dhn_neigh ) {
+ dhn_neigh->dhn = dhn;
+ dhn->neigh = dhn_neigh;
+ }
+
+ 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 (on)
+ free_orig_node(on);
+
+ 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)
+{
+
+ assertion( -500372, (ttn && (ttn)->dev ));
+
+ if (tx_creator_result != ((int) ((ttn)->frame_data_length_target))) {
+
+ dbgf(DBGL_CHANGES, 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 ((--((ttn)->tx_iterations)) == 0) {
+
+ (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;
+
+ debugFree((ttn), -300169);
+
+ return YES;
+ }
+
+ (ttn)->tx_timestamp = bmx_time;
+
+ return NO;
+}
+
+
+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)
+{
+ 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(DBGL_CHANGES, 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_SYS, 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 {
+
+ 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;
+
+ } else {
+
+ assertion( -500371, (frame_data_len));
+
+ ttn->frame_data_length_target = frame_data_len;
+ }
+
+ 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);
+ }
+
+
+}
+
+
+
+
+void purge_dev_tx_list( struct dev_node *dev ) {
+ int i;
+
+ paranoia( -500203, !dev );
+
+ for (i = 0; i < FRAME_TYPE_ARRSZ; i++) {
+
+ 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;
+ }
+
+ }
+}
+
+STATIC_FUNC
+void create_ogm_aggregation(void)
+{
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, " ");
+
+ uint32_t n = 0;
+
+ 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));
+
+ struct msg_ogm_adv* ogm = debugMalloc(target_aggregations * sizeof (struct
msg_ogm_adv), -300177);
+
+ static IID_T curr_iid = IID_MIN_USED;
+
+ if (curr_iid >= my_iid_repos.max_free)
+ curr_iid = IID_MIN_USED;
+
+ IID_T start_iid = curr_iid;
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "pending %d target %d start %d",
+ ogm_aggreg_pending, target_aggregations, start_iid);
+
+ do {
+ IID_NODE_T *dhn = my_iid_repos.arr.node[curr_iid];
+ struct orig_node *on;
+ int warn = 0;
+
+ while (dhn && (on = dhn->on) &&
+ GREAT_SQN(on->ogm_sqn_to_be_send &
on->path_metric_algo.sqn_mask, on->ogm_sqn_aggregated)) {
+
+ 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++;
+
+ dbgf(warn ? DBGL_CHANGES : DBGL_ALL, warn ? DBGT_WARN :
DBGT_INFO, "%s %s %d < %d",
+ on->id.name, warn ? "delayed!" :
"in-time",
+ on->ogm_sqn_aggregated, on->ogm_sqn_to_be_send);
+
+ on->ogm_sqn_aggregated = on->ogm_sqn_to_be_send &
on->path_metric_algo.sqn_mask;
+
+ ogm[n].orig_sqn = htons(on->ogm_sqn_to_be_send);
+ ogm[n].transmitterIID4x = htons(dhn->myIID4orig);
+
+ if ((++n) == target_aggregations)
+ goto create_ogm_aggregation_done;
+ }
+
+ if ((++curr_iid) >= my_iid_repos.max_free)
+ curr_iid = IID_MIN_USED;
+
+ } while (curr_iid != start_iid);
+
+create_ogm_aggregation_done:
+
+ if (curr_iid == start_iid)
+ ogm_aggreg_pending = 0;
+ else
+ ogm_aggreg_pending -= n;
+
+ if (ogm_aggreg_pending) {
+ dbgf(DBGL_SYS, DBGT_WARN, "%d ogms left for immediate next
aggregation", ogm_aggreg_pending);
+ }
+
+ if (!n) {
+ debugFree( ogm, -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->sqn = ++ogm_aggreg_sqn_max;
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "aggregation_sqn %d aggregated_ogms %d",
oan->sqn, n);
+
+ list_add_tail(&ogm_aggreg_list, &oan->list);
+
+ struct avl_node *an = NULL;
+ struct neigh_node *nn;
+
+ while ((nn = avl_iterate_item(&neigh_tree, &an))) {
+
+ bit_set(nn->ogm_aggregations_acked, OGM_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)
+{
+
+ static struct link_dev_node **lndev_arr = NULL;
+ static uint16_t lndev_arr_items = 0;
+ struct avl_node *an;
+ struct neigh_node *nn;
+ struct dev_node *dev;
+ uint16_t d = 0;
+
+ if (lndev_arr_items < dev_ip4_tree.items + 1) {
+
+ if (lndev_arr)
+ debugFree(lndev_arr, -300180);
+
+ lndev_arr_items = dev_ip4_tree.items + 1;
+ lndev_arr = debugMalloc((lndev_arr_items * sizeof (struct
link_dev_node*)), -300182);
+ }
+
+ if ( oan_criteria || dhn_criteria ) {
+
+ if (oan_criteria) {
+ dbgf(DBGL_CHANGES, DBGT_INFO, "aggreg_sqn %d ",
oan_criteria->sqn);
+ } else if (dhn_criteria) {
+ dbgf(DBGL_CHANGES, 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; (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) )
+ 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));
+
+ dbgf(DBGL_CHANGES, 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);
+
+ if (nn->best_rtq->key.dev->misc_flag == NO) {
+
+ lndev_arr[d++] = nn->best_rtq;
+
+ nn->best_rtq->key.dev->misc_flag = YES;
+ }
+
+ assertion(-500444, (d <= dev_ip4_tree.items));
+
+ }
+ }
+
+ lndev_arr[d] = NULL;
+
+ return lndev_arr;
+}
+
+STATIC_FUNC
+void schedule_and_purge_ogm_aggregations(struct dev_node *dev)
+{
+ static uint32_t timestamp = 0;
+
+ if (dev) {
+
+ dbgf(DBGL_CHANGES, 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))));
+
+ while (ogm_aggreg_pending && ((((uint32_t) bmx_time - timestamp))
>= DEF_OGM_AGGREG_INTERVAL)) {
+
+ 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) {
+
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "ogm_aggreg_list full min %d max %d items %d
unaggregated %d",
+ oan->sqn, ogm_aggreg_sqn_max,
ogm_aggreg_list.items, ogm_aggreg_pending);
+
+ debugFree(oan->ogm_advs, -300185);
+ debugFree(oan, -300186);
+ list_del_next(&ogm_aggreg_list, ((struct list_node*)
& ogm_aggreg_list));
+ }
+
+ create_ogm_aggregation();
+
+ if (!ogm_aggreg_pending)
+ timestamp = bmx_time;
+ }
+ }
+
+#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))));
+ }
+ }
+#endif
+
+ struct list_node *lpos, *tpos, *lprev = (struct list_node*) &
ogm_aggreg_list;
+
+ list_for_each_safe(lpos, tpos, &ogm_aggreg_list)
+ {
+ 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)) {
+
+ list_del_next(&ogm_aggreg_list, lprev);
+ debugFree(oan->ogm_advs, -300183);
+ debugFree(oan, -300184);
+
+ continue;
+
+ } else if ((((uint32_t) (bmx_time - oan->tx_timestamp)) >=
DEF_OGM_RESEND_INTERVAL) &&
+ oan->tx_attempts <= ogm_resend_attempts) {
+
+ struct link_dev_node **lndev_arr =
get_best_lndevs_by_criteria(oan, NULL);
+ int d;
+
+ 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);
+ }
+
+ if (!lndev_arr[0])
+ oan->tx_attempts = ogm_resend_attempts;
+
+ oan->tx_timestamp = bmx_time;
+ oan->tx_attempts++;
+ }
+
+ lprev = lpos;
+ }
+}
+
+
+STATIC_FUNC
+int tx_msg_hello40_reply(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff,
uint16_t buff_size)
+{
+ struct msg_hello_reply *hey0_rep = (struct msg_hello_reply *) (tx_buff);
+
+ hey0_rep->receiver_ip4 = ttn->dst_ip4;
+ hey0_rep->hello_dev_sqn = htons(ttn->sqn);
+
+ dbgf(DBGL_CHANGES, 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*/);
+
+ return sizeof (struct msg_hello_reply);
+}
+
+
+
+STATIC_FUNC
+int tx_msg_helloX0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff,
uint16_t buff_size)
+{
+
+ struct msg_hello_adv *hey0_adv = (struct msg_hello_adv *) (tx_buff);
+
+ hey0_adv->hello_dev_sqn = htons(++(ttn->dev->ogm_sqn));
+
+ struct avl_node *it;
+ 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)
+ continue;
+
+// update_lounged_metric(0, local_rtq_lounge, ttn->dev->ogm_sqn,
ttn->dev->ogm_sqn, &lndev->sqr[SQR_RTQ], local_lws);
+
+ update_metric(&lndev->mr[SQR_RTQ], &link_metric_algo[SQR_RTQ],
ttn->dev->ogm_sqn, ttn->dev->ogm_sqn, 0);
+ }
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s %s SQN %d", ttn->dev->name,
ttn->dev->ip4_str, ttn->dev->ogm_sqn);
+
+ 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)
+{
+ assertion( -500366 , (sizeof ( struct msg_description_request) == sizeof( struct
msg_dhash_request)));
+
+ struct msg_dhash_request *req = (struct msg_dhash_request *) (tx_buff);
+
+ req->receiver_ip4 = ttn->dst_ip4;
+ req->receiverIID4x = htons(ttn->neighIID4x);
+
+ dbgf(DBGL_CHANGES, 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);
+
+ return sizeof ( struct msg_description_request);
+}
+
+
+STATIC_FUNC
+int tx_msg_description0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff,
uint16_t buff_size)
+{
+ struct dhash_node *dhn = NULL;
+ struct msg_description_adv *desc0_adv = (struct msg_description_adv *) tx_buff;
+ struct description *desc0;
+
+ dbgf_all(DBGT_INFO, "ttn->myIID4x %d", ttn->myIID4x);
+
+ if (ttn->myIID4x == IID_RSVD_4YOU) {
+
+ desc0_adv->transmitterIID4x = htons(myIID4me);
+ desc0 = my_orig_node.desc0;
+ *flags |= FRAME_FLAG_firstIsSender;
+
+ } else if ((dhn = iid_get_node_by_myIID4x(ttn->myIID4x)) &&
dhn->on) {
+
+ assertion(-500437, (dhn->on && dhn->on->desc0));
+
+ desc0_adv->transmitterIID4x = htons(ttn->myIID4x);
+ desc0 = dhn->on->desc0;
+
+ } else {
+
+ dbgf(DBGL_SYS, DBGT_WARN, "unknown myIID4x %d !",
ttn->myIID4x);
+ return FAILURE;
+ }
+
+ uint16_t tlvs_len = ntohs(desc0->dsc_tlvs_len);
+
+ if (sizeof (struct msg_description_adv) + tlvs_len > buff_size)
+ return (buff_size + 1);
+
+ memcpy((char*) & desc0_adv->desc, (char*) desc0, sizeof (struct
description) + tlvs_len);
+
+ return sizeof (struct msg_description_adv) + tlvs_len;
+}
+
+
+
+
+STATIC_FUNC
+int tx_msg_dhash0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff,
uint16_t buff_size)
+{
+ struct msg_dhash_adv *dhash0_adv = (struct msg_dhash_adv *) tx_buff;
+ struct dhash_node *dhn;
+
+ if (ttn->myIID4x == IID_RSVD_4YOU) {
+
+ dhash0_adv->transmitterIID4x = htons(myIID4me);
+ dhn = my_orig_node.dhn;
+ *flags |= FRAME_FLAG_firstIsSender;
+
+ } else if ((dhn = iid_get_node_by_myIID4x(ttn->myIID4x)) &&
dhn->on) {
+
+ assertion(-500259, (dhn->on && dhn->on->desc0));
+
+ dhash0_adv->transmitterIID4x = htons(ttn->myIID4x);
+
+ } else {
+
+ dbgf(DBGL_SYS, DBGT_WARN, "unknown myIID4x %d !",
ttn->myIID4x);
+ return FAILURE;
+ }
+
+ memcpy((char*) & dhash0_adv->dhash, (char*) & dhn->dhash, sizeof (
struct description_hash));
+
+ return sizeof (struct msg_dhash_adv);
+}
+
+
+
+
+STATIC_FUNC
+int tx_frame_ogm0_advs(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff,
uint16_t buff_size)
+{
+ struct list_node *list_pos;
+
+ assertion(-500428, (ttn->frame_data_length_target <= buff_size));
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, " aggregation_sqn %d", ttn->sqn );
+
+ 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 ) {
+
+ ((struct hdr_ogm_adv*) tx_buff)->aggregation_sqn =
htons(ttn->sqn);
+
+ memcpy(tx_buff + sizeof (struct hdr_ogm_adv),
+ oan->ogm_advs, oan->aggregated_ogms * sizeof
(struct msg_ogm_adv));
+
+ assertion(-500429, (ttn->frame_data_length_target ==
+ (sizeof (struct hdr_ogm_adv) + oan->aggregated_ogms *
sizeof (struct msg_ogm_adv))));
+
+ return ttn->frame_data_length_target;
+
+ }
+ }
+
+ return FAILURE;
+}
+
+
+STATIC_FUNC
+int tx_msg_ogm_ack(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t
buff_size)
+{
+ struct msg_ogm_ack *ack = (struct msg_ogm_ack *) tx_buff;
+
+ ack->receiver_ip4 = ttn->dst_ip4;
+ ack->aggregation_sqn = htons(ttn->sqn);
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, " aggreg_sqn %d to %s", ttn->sqn,
ipStr(ttn->dst_ip4));
+
+ return sizeof (struct msg_ogm_ack);
+}
+
+
+STATIC_FUNC
+int rx_frame_ogm0_advs(struct packet_buff *pb, struct frame_header *frame)
+{
+ 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);
+
+ uint16_t msgs = (frame->length - (sizeof (struct frame_header) + sizeof
(struct hdr_ogm_adv))) /
+ sizeof (struct msg_ogm_adv);
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, " ");
+
+ if (!nn) {
+ dbgf(DBGL_CHANGES, 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;
+ }
+
+ schedule_tx_task(nn->best_rtq->key.dev, nn->best_rtq,
FRAME_TYPE_OGM0_ACKS, 0, aggregation_sqn, 0, 0);
+
+ 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)) {
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "already known
ogm_aggregation_sqn %d from neigh %s",
+ aggregation_sqn, nn->dhn->on->id.name);
+
+ return frame->length;
+ }
+
+ if (((uint16_t) (nn->ogm_aggregation_rcvd_max - aggregation_sqn)) >
OGM_AGGREG_SQN_CACHE_WARN) {
+
+ dbgf( DBGL_SYS, 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);
+ }
+
+ bit_set(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE,
aggregation_sqn, 1);
+
+ } else {
+
+ if (((uint16_t) (aggregation_sqn - nn->ogm_aggregation_rcvd_max)) >
OGM_AGGREG_SQN_CACHE_WARN) {
+
+ 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 );
+ }
+
+ bit_clear(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE,
nn->ogm_aggregation_rcvd_max + 1, aggregation_sqn);
+
+ bit_set(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE,
aggregation_sqn, 1);
+ nn->ogm_aggregation_rcvd_max = aggregation_sqn;
+
+ }
+
+ dbgf(DBGL_CHANGES, 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);
+
+ uint16_t m;
+ for (m = 0; m < msgs; m++) {
+
+ IID_T neighIID4x = ntohs(ogm[m].transmitterIID4x);
+ SQN_T orig_sqn = ntohs(ogm[m].orig_sqn);
+
+ IID_NODE_T *dhn = iid_get_node_by_neighIID4x(nn, neighIID4x );
+ struct orig_node *on = NULL;
+
+ if ( dhn == my_orig_node.dhn )
+ continue;
+
+
+ if (dhn && (on = dhn->on) && ((SQN_T) (orig_sqn -
on->ogm_sqn_min)) < on->ogm_sqn_range) {
+
+ dbgf(DBGL_CHANGES, 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);
+
+
+ } else {
+ dbgf(!dhn ? DBGL_CHANGES : DBGL_SYS, 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);
+
+ schedule_tx_task(nn->best_rtq->key.dev, nn->best_rtq,
FRAME_TYPE_DHS0_REQS, 0, 0, 0, neighIID4x);
+ }
+ }
+
+ return frame->length;
+}
+
+STATIC_FUNC
+int rx_frame_ogm40_acks(struct packet_buff *pb, struct frame_header *frame)
+{
+ struct msg_ogm_ack *ack = (struct msg_ogm_ack *) frame->data;
+ struct neigh_node *nn = pb->ln->neigh;
+
+ uint16_t msgs = (frame->length - (sizeof (struct frame_header))) / sizeof
(struct msg_ogm_ack);
+
+ 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;
+ }
+
+ uint16_t m;
+ for (m = 0; m < msgs; m++) {
+
+ if ( ack[m].receiver_ip4 != pb->iif->ip4_addr )
+ continue;
+
+ SQN_T aggregation_sqn = ntohs(ack[m].aggregation_sqn);
+
+ if (((uint32_t) (ogm_aggreg_sqn_max - aggregation_sqn) <
OGM_AGGREG_SQN_CACHE_RANGE)) {
+
+ bit_set(pb->ln->neigh->ogm_aggregations_acked,
OGM_AGGREG_SQN_CACHE_RANGE, aggregation_sqn, 1);
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "neigh %s sqn %d <=
sqn_max %d",
+ pb->neigh_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);
+
+ }
+ }
+ return frame->length;
+}
+
+
+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 *orig_dhn = NULL;
+ struct link_node *ln = pb->ln;
+ IDM_T invalid = NO;
+ struct description *cache = NULL;
+
+ if (avl_find(&dhash_invalid_tree, dhash)) {
+
+ invalid = YES;
+
+ } else if ((orig_dhn = avl_find_item(&dhash_tree, dhash))) {
+
+ if (ln->neigh) {
+
+ // this was just for testing eh??? assertion(-500375,
(ln->neigh->dhn == orig_dhn));
+
+ if (orig_dhn == my_orig_node.dhn) {
+
+ dbgf(DBGL_CHANGES, 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 (!is_sender) {
+
+ 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);
+
+ return FAILURE_POINTER;
+
+ } else if((ln->neigh->neighIID4neigh !=
neighIID4x)) {
+
+ 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);
+
+ }
+ }
+
+ if (is_sender)
+ update_neigh_node(ln, orig_dhn, neighIID4x);
+
+ else if (update_neighIID4x_repository(ln->neigh, neighIID4x,
orig_dhn) == FAILURE)
+ return FAILURE_POINTER;
+
+
+ } else {
+
+ if (is_sender) {
+ update_neigh_node(ln, orig_dhn, neighIID4x);
+ } else {
+ //update_neigh_node(ln, dhn, IID_RSVD_UNUSED);
+ //update_neigh_iid_repos(ln->neigh, neighIID4x, dhn);
+ }
+ }
+
+ } else {
+
+ // 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 ((orig_dhn = process_description(pb, cache, dhash))) {
+
+ update_neigh_node(ln, orig_dhn, neighIID4x);
+ }
+
+ } else if (ln->neigh && (cache =
rem_cached_description(dhash))) {
+
+ orig_dhn = process_description(pb, cache, dhash);
+
+ if (orig_dhn &&
update_neighIID4x_repository(ln->neigh, neighIID4x, orig_dhn) == FAILURE)
+ return FAILURE_POINTER;
+
+ }
+ }
+
+
+ dbgf(DBGL_CHANGES, 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],
+ (dsc ? "DESCRIPTION" : (cache ? "CACHED_DESCRIPTION"
: (orig_dhn?"KNOWN":"UNDESCRIBED"))),
+ neighIID4x, is_sender,
+ invalid ? "INVALIDATED" : (orig_dhn && orig_dhn->on
? orig_dhn->on->id.name : "---"));
+
+
+ return orig_dhn;
+}
+
+
+STATIC_FUNC
+int rx_frame_dhash0_advs(struct packet_buff *pb, struct frame_header *frame)
+{
+
+ 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) {
+
+ return FAILURE;
+
+ } else if (!dhn) {
+
+ schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DSC0_REQS,
0, 0, 0, neighIID4x);
+
+ }/* else if (dhn && is_sender && !pb->ln->neigh) {
+
+ schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_REQS,
0, 0, 0, IID_RSVD_4YOU);
+ }*/
+
+ paranoia(-500488, (dhn && is_sender &&
!pb->ln->neigh));
+
+
+ }
+ return frame->length;
+}
+
+
+STATIC_FUNC
+int rx_frame_description0_advs(struct packet_buff *pb, struct frame_header *frame)
+{
+
+ uint16_t pos = sizeof ( struct frame_header);
+
+ struct description_hash dhash0;
+
+ 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 description *desc0 = &adv->desc;
+ uint16_t tlvs_len = ntohs(desc0->dsc_tlvs_len);
+ IID_T neighIID4x = ntohs(adv->transmitterIID4x);
+ 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) {
+
+ 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;
+ }
+
+ 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);
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "rcvd %s desc0: %jX via %s NB
%s",
+ dhn ? "accepted" : "denied",
desc0->id.rand.u64[0], pb->iif->name, pb->neigh_str);
+
+
+ if (dhn == FAILURE_POINTER) {
+
+ return FAILURE;
+
+ } else if (dhn && dhn->on->updated_timestamp == bmx_time
&& pb->ln->neigh && DEF_UNSOLICITED_DESCRIPTIONS) {
+
+ struct link_dev_node **lndev_arr =
get_best_lndevs_by_criteria(NULL, pb->ln->neigh->dhn);
+ int d;
+
+ uint16_t desc_len = sizeof ( struct msg_description_adv) +
ntohs(dhn->on->desc0->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);
+
+
+ }
+
+
+ paranoia(-500379, (dhn && is_sender &&
!pb->ln->neigh));
+
+ pos += sizeof ( struct msg_description_adv) + tlvs_len;
+ }
+
+ if (frame->length != pos)
+ return FAILURE;
+
+
+ return frame->length;
+}
+
+STATIC_FUNC
+int rx_frame_dhash0_or_description0_requests(struct packet_buff *pb, struct frame_header
*frame)
+{
+ 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);
+
+ uint8_t frame_type = frame->type;
+
+
+ for (m = 0; m < n; m++) {
+
+ struct msg_description_request *req = &(((struct
msg_description_request*) (frame->data))[m]);
+ IID_T myIID4x = ntohs(req->receiverIID4x);
+ uint16_t desc0_len = 0;
+
+ dbg(DBGL_CHANGES, DBGT_INFO, "%s dest_llip4 %s myIID4x %d",
+ frame_handler[frame_type].name, ipStr(req->receiver_ip4),
myIID4x);
+
+ if ( req->receiver_ip4 != pb->iif->ip4_addr ) // if I am not
asked
+ continue;
+
+
+ if (myIID4x == IID_RSVD_4YOU || myIID4x == myIID4me) {
+
+ myIID4x = IID_RSVD_4YOU;
+
+ desc0_len = sizeof ( struct msg_description_adv) +
my_desc0_tlv_len;
+
+ } else { // if I am asked for somebody else description
+
+ struct dhash_node *dhn = iid_get_node_by_myIID4x(myIID4x);
+
+ assertion(-500270, (!(dhn && dhn->on &&
!dhn->on->desc0)));
+
+ if (myIID4x <= IID_RSVD_MAX || !dhn || !dhn->on ||
+ ((uint32_t) (bmx_time - dhn->referred_timestamp)) >
DEF_DESC0_REFERRED_TO) {
+
+ 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"));
+
+ continue;
+ }
+
+ assertion(-500251, (dhn && dhn->on &&
dhn->myIID4orig == myIID4x));
+ desc0_len = sizeof ( struct msg_description_adv) +
ntohs(dhn->on->desc0->dsc_tlvs_len);
+ }
+
+
+ if ( frame_type == FRAME_TYPE_DSC0_REQS) {
+
+ schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DSC0_ADVS,
desc0_len, 0, myIID4x, 0);
+
+ } else {
+
+ schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_ADVS,
0, 0, myIID4x, 0);
+ }
+ }
+
+ return frame->length;
+}
+
+STATIC_FUNC
+int rx_frame_hello40_replies(struct packet_buff *pb, struct frame_header *frame)
+{
+
+ int found = 0, m, n = (frame->length - sizeof (struct frame_header)) / sizeof
( struct msg_hello_reply);
+
+ for (m = 0; m < n; m++) {
+
+ struct msg_hello_reply *msg = &(((struct msg_hello_reply*)
(frame->data))[m]);
+
+ SQN_T sqn = ntohs(msg->hello_dev_sqn);
+
+ dbgf(DBGL_CHANGES, 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);
+
+ if ( msg->receiver_ip4 != pb->iif->ip4_addr )
+ continue;
+
+
+ if ((SQN_T) (pb->iif->ogm_sqn - sqn) > (SQN_T) local_rtq_lounge)
{
+
+ dbgf(DBGL_SYS, DBGT_INFO, "DAD-Alert invalid Link-Local SQN
%d!=%d from %s via %s",
+ sqn, pb->iif->ogm_sqn, pb->neigh_str,
pb->iif->name);
+
+ return FAILURE;
+ }
+
+ found++;
+
+ if( !pb->ln->neigh)
+ schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_REQS,
0, 0, 0, IID_RSVD_4YOU);
+
+ update_link_node(pb->ln, pb->iif, sqn, pb->iif->ogm_sqn,
SQR_RTQ, PROBE_RANGE);
+
+ }
+
+ if (found > 1) {
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "rcvd %d %s messages in %d-bytes frame",
+ found, frame_handler[FRAME_TYPE_HI40_REPS].name,
frame->length);
+ }
+
+ return frame->length;
+
+}
+
+
+
+STATIC_FUNC
+int rx_frame_helloX0_advs( struct packet_buff *pb, struct frame_header *frame )
+{
+
+ struct link_node *ln = pb->ln;
+
+ int m, n = (frame->length - sizeof (struct frame_header)) / sizeof ( struct
msg_hello_adv);
+
+ 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);
+ }
+
+ for (m = 0; m < n; m++) {
+
+ struct msg_hello_adv *msg = &(((struct msg_hello_adv*)
(frame->data))[m]);
+
+ SQN_T sqn = ntohs(msg->hello_dev_sqn);
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "NB %s via %s SQN %d ",
pb->neigh_str, pb->iif->name, sqn);
+
+ // 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)) {
+
+ 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);
+
+ update_link_node(ln, pb->iif, sqn, sqn, SQR_RQ, PROBE_RANGE);
+
+ }
+
+ return frame->length;
+}
+
+
+
+int rx_frames(struct packet_buff *pb, uint8_t* fdata, uint16_t fsize)
+{
+
+ uint16_t frm_pos = 0;
+ int t = 0, pt = 0;
+
+ struct frame_header *fhdr = NULL;
+ uint16_t flength = 0;
+
+ while (frm_pos + sizeof ( struct frame_header) < fsize) {
+
+ fhdr = (struct frame_header*) & (fdata[frm_pos]);
+ flength = fhdr->length = ntohs(fhdr->length);
+ int receptor_result;
+
+ if ((t = fhdr->type) < pt || flength < sizeof ( struct
frame_header) || flength + frm_pos > fsize) {
+
+ goto rx_frames_frm_error;
+ }
+
+ struct pkt_frame_handler *fhdl = &frame_handler[t];
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "type %s size %d flags 0x%X",
+ fhdl->name, flength, fhdr->flags);
+
+
+ if (t > FRAME_TYPE_NOP || !(fhdl->rx_frm_receptor)) {
+
+ dbgf(DBGL_SYS, DBGT_WARN, "unsupported type %d ! maybe you
need an update?", t);
+
+ if (t > FRAME_TYPE_NOP)
+ goto rx_frames_frm_error;
+
+ } else if (flength - sizeof (struct frame_header) <
fhdl->data_header_size + fhdl->min_msg_size) {
+
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "too small size %d for type %s", flength,
fhdl->name);
+ goto rx_frames_frm_error;
+
+ } else if (fhdl->fixed_msg_size &&
+ (flength - (sizeof (struct frame_header) +
fhdl->data_header_size)) % fhdl->min_msg_size) {
+
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "nonmaching size %d for type %s", flength,
fhdl->name);
+ goto rx_frames_frm_error;
+
+ } else if (fhdl->min_rtq && (!pb->lndev ||
pb->lndev->mr[SQR_RTQ].val < fhdl->min_rtq)) {
+
+ dbg_mute(60, DBGL_SYS, 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);
+
+ } else if (flength != (receptor_result = (*(fhdl->rx_frm_receptor))
(pb, fhdr))) {
+
+ if (receptor_result == FAILURE)
+ blacklist_neighbor(pb);
+
+ goto rx_frames_msg_error;
+
+ }
+
+ pt = t;
+ frm_pos += flength;
+ }
+
+ if ( frm_pos != fsize )
+ goto rx_frames_frm_error;
+
+ 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 ) {
+
+ int status;
+
+ dbgf_all( DBGT_INFO, "len %d", udp_len );
+
+ if ( send_sock == 0 )
+ return 0;
+
+ /*
+ 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;
+
+ status = sendmsg( send_sock, &m, 0 );
+ */
+
+ status = sendto( send_sock, upd_data, udp_len, 0, (struct sockaddr *)dst, sizeof(struct
sockaddr_in) );
+
+ 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));
+
+ } else {
+
+ dbg_mute( 60, DBGL_SYS, DBGT_ERR, "can't send udp packet via fd %d: %s",
send_sock, strerror(errno));
+
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+void tx_packet( void *dev_node )
+{
+ 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;
+
+ assertion( -500204, dev );
+ assertion( -500205, dev->active );
+
+ //remove_task( tx_packet, dev );
+ register_task(aggreg_interval - (1 + rand_num(aggreg_interval / 10)), tx_packet,
dev);
+
+ schedule_and_purge_ogm_aggregations(dev);
+
+ uint16_t type = 0; // the currently processed frame_type
+
+ while (type <= FRAME_TYPE_NOP) {
+
+ uint16_t length = sizeof (struct frame_header);
+ uint8_t flags = 0;
+
+ int creator_result;
+ struct pkt_frame_handler *fhdl = &frame_handler[type];
+ struct tx_task_node *ttn;
+ IDM_T frame_full = NO;
+
+ assertion(-500351, (!(fhdl->tx_frm_creator &&
fhdl->tx_msg_creator)));
+
+ if ((ttn = dev->my_tx_tasks[type])) {
+
+ assertion(-500422, (!fhdl->data_header_size));
+ assertion(-500424, (fhdl->tx_msg_creator));
+ assertion(-500441, (ttn->myIID4x == IID_RSVD_4YOU));
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s type %d=%s %s",
+ dev->name, type, fhdl->name, "from
dev->my_tx_tasks");
+
+ if (tx_task_obsolete(dev, type, ttn)) {
+
+ creator_result = FAILURE;
+
+ } else if (packet_full ||
+ (fhdl->fixed_msg_size &&
+ packet_size + length + ttn->frame_data_length_target
> (uint16_t) max_udpd_size)
+ ) {
+
+ creator_result = max_udpd_size + 1;
+
+ } else {
+
+ creator_result = (*(fhdl->tx_msg_creator))
+ (ttn, &flags, (tx_buff + packet_size +
length),
+ (max_udpd_size - (packet_size + length)));
+
+ }
+
+ if (creator_result > (max_udpd_size - (packet_size + length)))
{
+
+ assertion(-500431,
+ (packet_size > sizeof ( struct packet_header)
||
+ length > sizeof (struct frame_header)));
+
+ packet_full = YES;
+
+ } else if (creator_result) {
+
+ if (creator_result > 0)
+ length += creator_result;
+
+ freed_tx_task_node(ttn, creator_result, NULL);
+
+ }
+ }
+
+ struct list_node *lprev = (struct list_node*)
&(dev->tx_tasks_list[type]);
+ struct list_node *lpos, *ltmp;
+
+ list_for_each_safe(lpos, ltmp, &(dev->tx_tasks_list[type]))
+ {
+ ttn = list_entry(lpos, struct tx_task_node, list);
+
+ assertion(-500440, (ttn->frame_type == type));
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s type %d=%s %s",
+ dev->name, type, fhdl->name, "from
dev->tx_tasks_list");
+
+ if (ttn->tx_timestamp == bmx_time) {
+
+ // just send! send again later;
+ creator_result = 0;
+
+ } else if (tx_task_obsolete(dev, type, ttn)) {
+
+ creator_result = FAILURE;
+
+ } else if (packet_full ||
+ (fhdl->fixed_msg_size &&
+ packet_size + length + ttn->frame_data_length_target
> (uint16_t) max_udpd_size)
+ ) {
+
+ creator_result = max_udpd_size + 1;
+
+ } else if (fhdl->tx_frm_creator) {
+
+ creator_result = ((*(fhdl->tx_frm_creator))
+ (ttn, &flags, (tx_buff + packet_size +
length),
+ (max_udpd_size - (packet_size + length))));
+
+ frame_full = YES;
+
+ } else {
+
+ assertion(-500425, (fhdl->tx_msg_creator));
+ assertion(-500426, (!fhdl->data_header_size)); // to
be implemented...
+
+ creator_result = (*(fhdl->tx_msg_creator))
+ (ttn, &flags, (tx_buff + packet_size +
length),
+ (max_udpd_size - (packet_size + length)));
+
+ }
+
+ if (creator_result > (max_udpd_size - (packet_size + length)))
{
+
+ assertion(-500430,
+ (packet_size > sizeof ( struct packet_header)
||
+ length > sizeof (struct frame_header)));
+
+ packet_full = YES;
+ break;
+
+ } else if (creator_result) {
+
+ if (creator_result > 0)
+ length += creator_result;
+
+ if (freed_tx_task_node(ttn, creator_result, lprev) ==
NO)
+ lprev = lpos;
+
+ if (frame_full)
+ break;
+
+ continue;
+
+ } else {
+ lprev = lpos;
+ }
+ }
+
+
+ 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;
+
+ dbgf(DBGL_ALL, DBGT_INFO, "send frame type %s size
%d", fhdl->name, length);
+ }
+
+
+ if (packet_full || (type == FRAME_TYPE_NOP && packet_size >
sizeof ( struct packet_header))) {
+
+ assertion(-500208, (packet_size <= max_udpd_size));
+ assertion(-500412, (packet_size >= 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));
+
+ send_udp_packet(tx_buff, packet_size,
&dev->ip4_netwbrc_addr, dev->unicast_sock);
+
+ dbgf(DBGL_ALL, DBGT_INFO, "send packet size %d via dev
%s", packet_size, dev->name);
+
+ packet_size = sizeof ( struct packet_header);
+ packet_full = NO;
+ }
+
+ 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) {
+
+ CHECK_INTEGRITY();
+
+ type++;
+ }
+ }
+}
+
+
+
+void schedule_my_hello_message( void* dev_node ) {
+
+ struct dev_node * dev = dev_node;
+
+ paranoia( -500206, !dev );
+ paranoia( -500207, !dev->active );
+
+ register_task( my_hello_interval, schedule_my_hello_message, dev );
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "%s", dev->name);
+
+ if (!LIST_EMPTY(&(dev->tx_tasks_list[FRAME_TYPE_HI40_ADVS]))) {
+ dbgf( DBGL_SYS, DBGT_ERR, " ");
+ }
+
+ schedule_tx_task( dev, NULL, FRAME_TYPE_HI40_ADVS, 0, 0, 0, 0 );
+}
+
+
+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;
+
+ 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(DBGL_CHANGES, DBGT_INFO, "ogm_sqn %d",
my_orig_node.ogm_sqn_to_be_send);
+
+ } else {
+
+ update_my_description_adv();
+
+ }
+}
+
+
+
+
+void update_my_description_adv(void)
+{
+ struct description_hash dhash;
+ struct description *dsc = my_orig_node.desc0;
+
+ if ( terminating() )
+ return;
+
+ // put obligatory stuff:
+ memset(dsc, 0, MAX_PKT_MSG_SIZE);
+
+ memcpy(&dsc->id, &my_orig_node.id, sizeof(struct description_id));
+/*
+ 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]);
+*/
+
+
+ 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);
+
+ // 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);
+
+ 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);
+
+ 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);
+
+ 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;
+
+
+ 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);
+
+
+ dsc->ttl_max = my_ttl;
+ dsc->path_hystere = my_path_hystere;
+
+ dsc->hop_penalty = my_hop_penalty;
+ dsc->late_penalty = my_late_penalty;
+ dsc->asym_weight = asym_weight;
+ dsc->sym_weight = sym_weight;
+
+
+ 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);
+
+ dsc->dsc_sqn = htons(++(my_orig_node.desc0_sqn));
+
+
+ dsc->path_ogi = htons(my_ogm_interval);
+
+
+ // add all tlv options:
+ my_desc0_tlv_len = 0;
+ uint8_t tlvt;
+ for ( tlvt=0; tlvt < BMX_DSC_TLV_ARRSZ; tlvt++) {
+
+ struct frame_header *tlv = (struct frame_header*) (((char*) dsc) + sizeof
(struct description) + my_desc0_tlv_len);
+
+ uint16_t rsvd = my_desc0_tlv_len + sizeof (struct frame_header);
+
+ if (rsvd <= MAX_DESC0_TLV_SIZE &&
(description0_tlv_handler[tlvt].create_tlv)) {
+
+ uint16_t msgs_size =
(*(description0_tlv_handler[tlvt].create_tlv))
+ (tlv->data, MAX_DESC0_TLV_SIZE - rsvd);
+
+ if ( msgs_size ) {
+
+ assertion(-500355,
(description0_tlv_handler[tlvt].variable_msg_size ||
+ msgs_size %
description0_tlv_handler[tlvt].min_msg_size == 0));
+
+ tlv->type = tlvt;
+ tlv->length = htons(sizeof (struct frame_header) +
msgs_size);
+
+ my_desc0_tlv_len += sizeof (struct frame_header) +
msgs_size;
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "added %s size
%d",
+ description0_tlv_handler[tlvt].name, msgs_size);
+
+ }
+
+ } else {
+ cleanup_all( -500352 );
+ }
+ }
+
+ dsc->dsc_tlvs_len = htons(my_desc0_tlv_len);
+
+ dbgf(DBGL_CHANGES, DBGT_INFO, "added tlv total of %d ",
my_desc0_tlv_len);
+
+ // 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);
+
+ if ( my_orig_node.dhn ) {
+ my_orig_node.dhn->on = NULL;
+ invalidate_dhash_node( my_orig_node.dhn );
+ }
+
+ my_orig_node.dhn = create_dhash_node(&dhash, &my_orig_node);
+
+ myIID4me = my_orig_node.dhn->myIID4orig;
+
+ 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);
+ 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);
+ }
+
+/*
+ remove_task(schedule_my_originator_message, NULL);
+ register_task(1, schedule_my_originator_message, NULL);
+*/
+
+
+}
+
+
+
+static 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,
+ 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,
+ 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"}
+
+};
+
+
+void init_msg( void )
+{
+
+ paranoia( -500347, ( sizeof(struct description_hash) != BMX_HASH0_LEN));
+
+ ogm_aggreg_sqn_max = rand_num(MAX_SQN);
+
+ register_options_array( msg_options, sizeof( msg_options ) );
+
+ InitSha(&bmx_sha);
+
+ register_task(rand_num(RAND_INIT_DELAY), schedule_my_originator_message, NULL);
+
+}
+
+void cleanup_msg( void )
+{
+ schedule_and_purge_ogm_aggregations(NULL /*purge_all*/);
+
+ debugFree(get_best_lndevs_by_criteria(NULL, NULL), -300218);
+
+ purge_cached_descriptions(YES);
+
+}
Added: trunk/bmx/msg.h
===================================================================
--- trunk/bmx/msg.h (rev 0)
+++ trunk/bmx/msg.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,357 @@
+/*
+ * 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.
+ *
+ * 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 <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#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 ARG_HELLO_INTERVAL "hello_interval"
+#define DEF_HELLO_INTERVAL DEF_OGM_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 2000
+#define MIN_OGM_INTERVAL 200
+#define MAX_OGM_INTERVAL 60000
+extern int32_t my_ogm_interval;
+
+
+#define DEF_TX_TS_TREE_SIZE 100
+#define DEF_TX_TS_TREE_PURGE_FK 5
+
+
+
+#define MIN_OGM_AGGREG_INTERVAL ( MIN_OGM_INTERVAL/10 )
+#define MAX_OGM_AGGREG_INTERVAL ( DEF_OGM_INTERVAL/2 )
+#define DEF_OGM_AGGREG_INTERVAL ( DEF_OGM_INTERVAL/5 )
+
+#define MAX_OGM_RESEND_INTERVAL (MAX_AGGREG_INTERVAL * 2)
+#define DEF_OGM_RESEND_INTERVAL ((DEF_AGGREG_INTERVAL * 2) / 3)
+
+#define MIN_OGM_RESEND_ATTEMPTS 0
+#define MAX_OGM_RESEND_ATTEMPTS 5
+#define DEF_OGM_RESEND_ATTEMPTS 3
+#define ARG_OGM_RESEND_ATTEMPTS "ogm_resend_attempts"
+
+#define MIN_NBDISC_RTQ (PROBE_RANGE / 8)
+#define MIN_OGM_ACK_RTQ (PROBE_RANGE / 4)
+
+
+
+
+//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 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 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
+} __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
+
+
+/*
+ * dhash0_adv or description0_adv specific frame flag
+ * firstIsSender flag is usefull to accelerate neighbor (and neighIID) discovery process
+ */
+
+#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
+} __attribute__((packed));
+
+
+struct msg_hello_adv {
+ SQN_T hello_dev_sqn;
+} __attribute__((packed));
+/*
+ * reception trigger:
+ * - update_link_nodes()
+ * - msg_hellp40_reply[]
+ *
+ */
+
+struct msg_hello_reply {
+ IP4_T receiver_ip4;
+ SQN_T hello_dev_sqn;
+} __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;
+} __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
+} __attribute__((packed));
+/*
+ * reception triggers:
+ * - msg_dhash0_adv[ ]
+ *
+ */
+
+
+struct msg_dhash_adv {
+ IID_T transmitterIID4x; //orig_sid
+ 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[]
+ *
+ */
+
+
+
+struct description {
+ struct description_id id;
+
+ 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;
+
+ uint16_t path_ogi;
+
+ uint16_t path_window_size;
+ uint16_t path_lounge_size;
+
+ uint8_t path_hystere;
+ uint8_t ttl_max;
+
+ 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
+
+// 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_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;
+} __attribute__((packed));
+
+struct hdr_ogm_adv {
+ SQN_T aggregation_sqn;
+ struct msg_ogm_adv msg[];
+} __attribute__((packed));
+
+/*
+ * reception triggers:
+ * - (if link <-> neigh <-... is known and orig_sid is NOT known)
msg_dhash0_request[ ... orig_did = orig_sid ]
+ * - else update_orig(orig_sid, orig_sqn)
+ */
+
+struct msg_ogm_ack {
+// IID_T transmitterIID4receiver;
+ IP4_T receiver_ip4;
+ SQN_T aggregation_sqn;
+} __attribute__((packed));
+/*
+ * reception triggers:
+ * - (if link <-> neigh <-... is known and orig_sid is NOT known)
msg_dhash0_request[ ... orig_did = orig_sid ]
+ * - else update_orig(orig_sid, orig_sqn)
+ */
+
+
+
+
+
+#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));
+
+
+
+
+
+
+struct description_cache_node {
+ struct description_hash dhash;
+ uint32_t timestamp;
+ struct description *description;
+};
+
+#define DEF_DESC0_CACHE_SIZE 3
+#define DEF_DESC0_CACHE_TO 100000
+
+#define DEF_UNSOLICITED_DESCRIPTIONS YES
+
+
+extern char *tlv_op_str[];
+
+extern uint32_t ogm_aggreg_pending;
+
+/***********************************************************
+ The core frame/message structures and handlers
+************************************************************/
+
+void update_my_description_adv( void );
+
+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 init_msg( void );
+
+void cleanup_msg( void );
+
+
Added: trunk/bmx/plugin.c
===================================================================
--- trunk/bmx/plugin.c (rev 0)
+++ trunk/bmx/plugin.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,569 @@
+/*
+ * 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.
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+#include "bmx.h"
+#include "msg.h"
+#include "plugin.h"
+#include "schedule.h"
+#include "hna.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);
+
+
+int32_t plugin_data_registries[PLUGIN_DATA_SIZE];
+
+
+void cb_plugin_hooks( void* data, int32_t cb_id ) {
+
+ struct list_node *list_pos;
+ struct plugin_node *pn, *prev_pn = NULL;
+
+ list_for_each( list_pos, &plugin_list ) {
+
+ 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 );
+
+ 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);
+
+}
+
+
+
+STATIC_FUNC
+int32_t configure_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;
+
+ if ( !cb_type || !cb_handler ) {
+ cleanup_all( -500143 );
+ }
+
+ list_for_each_safe( list_pos, tmp_pos, cb_list ) {
+
+ cbn = list_entry( list_pos, struct cb_node, list );
+
+ if ( cb_type == cbn->cb_type && cb_handler == cbn->cb_handler ) {
+
+ if ( del ) {
+
+ list_del_next(((struct list_head*) cb_list), prev_pos);
+ debugFree( cbn, -300069 );
+ return SUCCESS;
+
+ } 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;
+ }
+}
+
+
+
+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;
+}
+
+
+
+
+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 );
+}
+
+
+//notify interested plugins of rcvd packet...
+// 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 ) {
+
+ 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);
+
+ return calls;
+}
+
+
+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 );
+}
+
+
+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;
+ }
+
+ }
+
+ return CB_OGM_ACCEPT;
+}
+
+
+#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 ( 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;
+}
+
+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;
+
+}
+
+
+#endif
+
+
+int32_t reg_plugin_data( uint8_t data_type ) {
+
+ static int initialized = NO;
+
+ if ( !initialized ) {
+ memset( plugin_data_registries, 0, sizeof( plugin_data_registries ) );
+ initialized=YES;
+ }
+
+ if ( on_the_fly || 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);
+}
+
+#ifdef WITHUNUSED
+void **get_plugin_data( void *data, uint8_t data_type, int32_t registry ) {
+
+ if ( data_type >= PLUGIN_DATA_SIZE || registry >
plugin_data_registries[data_type] ) {
+ cleanup_all( -500145 );
+ //dbgf( DBGL_SYS, DBGT_ERR, "requested to deliver data for unknown registry
!");
+ //return NULL;
+ }
+
+ if ( data_type == PLUGIN_DATA_ORIG )
+ return &(((struct orig_node*)data)->plugin_data[registry]);
+
+ return NULL;
+}
+#endif
+
+STATIC_FUNC
+int is_plugin_active( void *plugin ) {
+
+ struct list_node *list_pos;
+
+ list_for_each( list_pos, &plugin_list ) {
+
+ if ( ((struct plugin_node *) (list_entry( list_pos, struct plugin_node, list
)))->plugin == plugin )
+ return YES;
+
+ }
+
+ 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;
+
+ 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)) {
+
+ 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
+ );
+
+ 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;
+
+ 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;
+
+}
+
+STATIC_FUNC
+void deactivate_plugin( void *p ) {
+
+ if ( !is_plugin_active( p ) ) {
+ cleanup_all( -500190 );
+ }
+
+ struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&plugin_list;
+
+ list_for_each_safe( list_pos, tmp_pos, &plugin_list ) {
+
+ struct plugin_node *pn = list_entry( list_pos, struct plugin_node, list );
+
+ if ( pn->plugin == 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_v2->plugin_name );
+
+ if ( pn->plugin_v2->cb_cleanup )
+ (*( pn->plugin_v2->cb_cleanup )) ();
+
+
+ if ( pn->dlname)
+ debugFree( pn->dlname, -300070);
+
+ debugFree( pn, -300071);
+
+ } else {
+
+ prev_pos = &pn->list;
+
+ }
+
+ }
+
+}
+
+STATIC_FUNC
+int8_t activate_dyn_plugin( const char* name ) {
+
+ struct plugin_v2* (*get_plugin_v2) ( void ) = NULL;
+
+ void *dlhandle;
+ struct plugin_v2 *pv1;
+ char dl_path[1000];
+
+ char *My_libs = getenv(BMX_ENV_LIB_PATH);
+
+ if ( !name )
+ return FAILURE;
+
+ // dl_open sigfaults on some systems without reason.
+ // removing the dl files from BMX_DEF_LIB_PATH is a way to prevent calling dl_open.
+ // Therefore we restrict dl search to BMX_DEF_LIB_PATH and BMX_ENV_LIB_PATH and ensure
that dl_open
+ // is only called if a file with the requested dl name could be found.
+
+ if ( My_libs )
+ sprintf( dl_path, "%s/%s", My_libs, name );
+ else
+ sprintf( dl_path, "%s/%s", BMX_DEF_LIB_PATH, name );
+
+
+ dbgf_all( DBGT_INFO, "trying to load dl %s", dl_path );
+
+ int dl_tried = 0;
+
+ if ( check_file( dl_path, NO, YES ) == SUCCESS &&
+ (dl_tried = 1) && (dlhandle = dlopen( dl_path, RTLD_NOW )) )
+ {
+
+ dbgf_all( DBGT_INFO, "succesfully loaded dynamic library %s", dl_path );
+
+ } else {
+
+ dbg( dl_tried ? DBGL_SYS : DBGL_CHANGES, dl_tried ? DBGT_ERR : DBGT_WARN,
+ "failed loading dl %s %s (maybe incompatible binary/lib versions?)",
+ dl_path, dl_tried?dlerror():"" );
+
+ return FAILURE;
+
+ }
+
+ dbgf_all( DBGT_INFO, "survived dlopen()!" );
+
+
+ typedef struct plugin_v2* (*sdl_init_function_type) ( void );
+
+ union {
+ sdl_init_function_type func;
+ void * obj;
+ } alias;
+
+ alias.obj = dlsym( dlhandle, "get_plugin_v2");
+
+ if ( !( get_plugin_v2 = alias.func ) ) {
+ dbgf( DBGL_SYS, DBGT_ERR, "dlsym( %s ) failed: %s", name, dlerror() );
+ return FAILURE;
+ }
+
+
+ if ( !(pv1 = get_plugin_v2()) ) {
+
+ dbgf( DBGL_SYS, DBGT_ERR, "get_plugin_v2( %s ) failed", name );
+ return FAILURE;
+
+ }
+
+ 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;
+
+ }
+
+ dbg( DBGL_CHANGES, DBGT_INFO,
+ "loading and activating %s dl %s succeeded",
+ My_libs ? "customized" : "default", dl_path );
+
+ 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 ) {
+
+ dbgf_all( DBGT_INFO, "%s %d", opt_cmd2str[cmd], _save );
+
+ char tmp_name[MAX_PATH_SIZE] = "";
+
+
+ if ( cmd == OPT_CHECK ) {
+
+ dbgf_all( DBGT_INFO, "about to load dl %s", patch->p_val );
+
+ if ( wordlen(patch->p_val)+1 >= MAX_PATH_SIZE || patch->p_val[0] ==
'/' )
+ return FAILURE;
+
+ wordCopy( tmp_name, patch->p_val );
+
+ if ( get_opt_parent_val( opt, tmp_name ) )
+ return SUCCESS;
+
+ if ( activate_dyn_plugin( tmp_name ) == FAILURE )
+ return FAILURE;
+
+ }
+
+ return SUCCESS;
+}
+
+static struct opt_type plugin_options[]=
+{
+// ord parent long_name shrt
Attributes *ival min max default *func,*syntax,*help
+
+ //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"}
+};
+
+
+void 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;
+
+ pv1=NULL;
+
+ // 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 ) );
+
+
+ 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 );
+#endif
+
+#endif
+}
+
+void cleanup_plugin( void ) {
+
+ while ( !LIST_EMPTY( &plugin_list ) )
+ deactivate_plugin( ((struct plugin_node*)(list_entry( (&plugin_list)->next,
struct plugin_node, list)))->plugin );
+
+}
Added: trunk/bmx/plugin.h
===================================================================
--- trunk/bmx/plugin.h (rev 0)
+++ trunk/bmx/plugin.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ *
+ * 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 PLUGIN_VERSION_02 0x02
+#define BMX_LIB_UCI_CONFIG "bmx_uci_config.so"
+
+#define ARG_PLUGIN "plugin"
+
+extern struct list_head cb_fd_list;
+
+
+
+enum {
+ PLUGIN_CB_CONF,
+ PLUGIN_CB_ORIG_CREATE,
+ PLUGIN_CB_ORIG_FLUSH,
+ PLUGIN_CB_ORIG_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 );
+
+ //some more advanced (rarely called) callbacks hooks
+ void (*cb_plugin_handler[PLUGIN_CB_SIZE]) (void*);
+
+ //some other attributes
+ uint8_t link_flags;
+
+};
+
+
+
+struct plugin_node {
+ struct list_node list;
+ int32_t version;
+ void *plugin;
+ struct plugin_v2 *plugin_v2;
+ void *dlhandle;
+ char *dlname;
+};
+
+
+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 );
+};
+
+
+struct cb_fd_node {
+ struct list_node list;
+ int32_t fd;
+ void (*cb_fd_handler) (int32_t fd);
+};
+
+
+struct cb_packet_node {
+ struct list_node list;
+ int32_t packet_type;
+ void (*cb_packet_handler) (struct packet_buff *);
+};
+
+
+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 );
+};
+
+
+// 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 );
+
+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
+};
+*/
+
+// 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 );
+
+//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
+};
+
+extern int32_t plugin_data_registries[PLUGIN_DATA_SIZE];
+
+
+int32_t reg_plugin_data( uint8_t data_type );
+
+#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 );
+
+
+//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 );
+
+int32_t cb_snd_ext_hook( uint16_t ext_type, unsigned char* ext_buff );
+
+// use void change_selects( void ) to trigger cb_fd_handler()
+
+
Added: trunk/bmx/route.c
===================================================================
--- trunk/bmx/route.c (rev 0)
+++ trunk/bmx/route.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,2218 @@
+/*
+ * 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, int32_t ifi, 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, ifi, 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;
+}
+
+
Added: trunk/bmx/route.h
===================================================================
--- trunk/bmx/route.h (rev 0)
+++ trunk/bmx/route.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,132 @@
+/*
+ * 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 );
+
Added: trunk/bmx/schedule.c
===================================================================
--- trunk/bmx/schedule.c (rev 0)
+++ trunk/bmx/schedule.c 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,661 @@
+/*
+ * 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.
+ *
+ * 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 <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h> /* ifr_if, ifr_tun */
+#include <linux/rtnetlink.h>
+
+
+#include "bmx.h"
+#include "msg.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 int32_t receive_max_sock = 0;
+static fd_set receive_wait_set;
+
+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 ) {
+ changed_readfds++;
+}
+
+
+static void check_selects( void ) {
+
+ if( changed_readfds == 0 )
+ return;
+
+ struct list_node *list_pos;
+
+ dbgf_all( DBGT_INFO, "%d select fds changed... ", changed_readfds );
+
+ changed_readfds = 0;
+
+ FD_ZERO(&receive_wait_set);
+ receive_max_sock = 0;
+
+ receive_max_sock = ifevent_sk;
+ FD_SET(ifevent_sk, &receive_wait_set);
+
+ if ( receive_max_sock < unix_sock )
+ receive_max_sock = unix_sock;
+
+ FD_SET(unix_sock, &receive_wait_set);
+
+ list_for_each( list_pos, &ctrl_list ) {
+
+ struct ctrl_node *cn = list_entry( list_pos, struct ctrl_node, list );
+
+ if ( cn->fd > 0 && cn->fd != STDOUT_FILENO ) {
+
+ receive_max_sock = MAX( receive_max_sock, cn->fd);
+
+ FD_SET( cn->fd, &receive_wait_set );
+ }
+ }
+
+ struct avl_node *it=NULL;
+ struct dev_node *bif;
+ while ((bif = avl_iterate_item(&dev_ip4_tree, &it))) {
+
+ if ( bif->active && bif->linklayer != VAL_DEV_LL_LO ) {
+
+ receive_max_sock = MAX( receive_max_sock, bif->unicast_sock );
+
+ FD_SET(bif->unicast_sock, &receive_wait_set);
+
+ receive_max_sock = MAX( receive_max_sock, bif->netwbrc_sock );
+
+ FD_SET(bif->netwbrc_sock, &receive_wait_set);
+
+ if (bif->fullbrc_sock > 0) {
+
+ receive_max_sock = MAX( receive_max_sock, bif->fullbrc_sock );
+
+ FD_SET(bif->fullbrc_sock, &receive_wait_set);
+
+ }
+ }
+ }
+
+ list_for_each( list_pos, &cb_fd_list ) {
+
+ struct cb_fd_node *cdn = list_entry( list_pos, struct cb_fd_node, list );
+
+ receive_max_sock = MAX( receive_max_sock, cdn->fd );
+
+ FD_SET( cdn->fd, &receive_wait_set );
+
+ }
+
+}
+
+
+
+
+
+void register_task( uint32_t timeout, void (* task) (void *), void *data )
+{
+
+ assertion(-500475, (remove_task(task, data) == FAILURE));
+
+ struct list_node *list_pos, *prev_pos = (struct list_node *)&task_list;
+ struct task_node *tmp_tn = NULL;
+
+
+ //TODO: allocating and freeing tn and tn->data may be much faster when done by
registerig function..
+ struct task_node *tn = debugMalloc( sizeof( struct task_node ), -300034 );
+ memset( tn, 0, sizeof(struct task_node) );
+
+ tn->expire = bmx_time + timeout;
+ tn->task = task;
+ tn->data = data;
+
+
+ list_for_each( list_pos, &task_list ) {
+
+ tmp_tn = list_entry( list_pos, struct task_node, list );
+
+ if ( GREAT_U32(tmp_tn->expire, tn->expire) ) {
+
+ list_add_after(&task_list, prev_pos, &tn->list);
+ break;
+
+ }
+
+ prev_pos = &tmp_tn->list;
+
+ }
+
+ if ( ( tmp_tn == NULL ) || ( LSEQ_U32(tmp_tn->expire, tn->expire) ))
+ list_add_tail(&task_list, &tn->list);
+
+}
+
+IDM_T remove_task( void (* task) (void *), void *data ) {
+
+ struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&task_list;
+ IDM_T ret = FAILURE;
+
+ list_for_each_safe( list_pos, tmp_pos, &task_list ) {
+
+ struct task_node *tn = list_entry( list_pos, struct task_node, list );
+
+ if ( tn->task == task && tn->data == data ) {
+
+ list_del_next(&task_list, prev_pos);
+
+ debugFree( tn, -300080 );
+#ifdef NO_PARANOIA
+ return SUCCESS;
+#else
+ assertion(-500474, (ret == FAILURE));
+ ret = SUCCESS;
+#endif
+
+ } else {
+
+ prev_pos = list_pos;
+ }
+ }
+
+ return ret;
+}
+
+
+uint32_t whats_next( void ) {
+
+ struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&task_list;
+
+ paranoia( -500175, sim_paranoia );
+
+ 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 ) ) {
+
+
+ list_del_next( &task_list, prev_pos );
+
+ (*(tn->task)) (tn->data);
+
+ debugFree( tn, -300081 );
+
+ CHECK_INTEGRITY();
+
+ return 0;
+
+ } else {
+
+ return tn->expire - bmx_time;
+ }
+ }
+
+ return MAX_SELECT_TIMEOUT_MS;
+}
+
+
+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_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) );
+ ifevent_sk = 0;
+ return -1;
+ }
+
+
+ unix_opts = fcntl( ifevent_sk, F_GETFL, 0 );
+ fcntl( ifevent_sk, F_SETFL, unix_opts | O_NONBLOCK );
+
+ if ( ( bind( ifevent_sk, (struct sockaddr*)&sa, sizeof(sa) ) ) < 0 ) {
+ dbg( DBGL_SYS, DBGT_ERR, "can't bind af_netlink socket for reacting on if
up/down events: %s",
+ strerror(errno) );
+ ifevent_sk = 0;
+ return -1;
+ }
+
+ change_selects();
+
+ return ifevent_sk;
+}
+
+static void close_ifevent_netlink_sk( void ) {
+
+ if ( ifevent_sk > 0 )
+ close( ifevent_sk );
+
+ ifevent_sk = 0;
+}
+
+static void recv_ifevent_netlink_sk( void ) {
+ char buf[4096]; //test this with a very small value !!
+
+ struct sockaddr_nl sa;
+
+ struct iovec iov;
+
+ memset(&iov, 0, sizeof (struct iovec));
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof (buf);
+
+ struct msghdr msg; // = {(void *) & sa, sizeof (sa), &iov, 1, NULL, 0,
0};
+ memset( &msg, 0, sizeof( struct msghdr));
+ msg.msg_name = (void *)&sa;
+ msg.msg_namelen = sizeof(sa); /* Length of address data. */
+ msg.msg_iov = &iov; /* Vector of data to send/receive into. */
+ msg.msg_iovlen = 1; /* Number of elements in the vector. */
+
+ while( recvmsg (ifevent_sk, &msg, 0) > 0 );
+
+ //so fare I just want to consume the pending message...
+}
+
+
+
+
+
+
+
+
+
+void wait4Event( uint32_t timeout ) {
+
+ static struct packet_buff pb;
+
+ uint32_t last_get_time_result = 0;
+
+ static uint32_t addr_len = sizeof(struct sockaddr_in);
+
+ uint32_t return_time = bmx_time + timeout;
+ struct timeval tv;
+ struct list_node *list_pos;
+ int selected;
+ fd_set tmp_wait_set;
+
+
+loop4Event:
+
+ while ( GREAT_U32(return_time, bmx_time) ) {
+
+ check_selects();
+
+ memcpy( &tmp_wait_set, &receive_wait_set, sizeof(fd_set) );
+
+ tv.tv_sec = (return_time - bmx_time) / 1000;
+ tv.tv_usec = ( (return_time - bmx_time) % 1000 ) * 1000;
+
+ selected = select( receive_max_sock + 1, &tmp_wait_set, NULL, NULL, &tv );
+
+ upd_time( &(pb.tv_stamp) );
+
+ //omit debugging here since event could be a closed -d4 ctrl socket
+ //which should be removed before debugging
+ //dbgf_all( DBGT_INFO, "timeout %d", timeout );
+
+ if ( bmx_time < last_get_time_result ) {
+
+ last_get_time_result = bmx_time;
+ dbg( DBGL_SYS, DBGT_WARN, "detected Timeoverlap..." );
+
+ goto wait4Event_end;
+ }
+
+ 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) );
+
+ wait_sec_msec( 0, 1 );
+ upd_time( NULL );
+
+ goto wait4Event_end;
+
+ }
+
+ if ( selected == 0 ) {
+
+ //Often select returns just a few milliseconds before being scheduled
+ if ( LESS_U32( return_time, (bmx_time + 10) ) ) {
+
+ //cheating time :-)
+ bmx_time = return_time;
+
+ goto wait4Event_end;
+ }
+
+ //if ( LESS_U32( return_time, bmx_time ) )
+ dbg_mute( 50, DBGL_CHANGES, DBGT_WARN,
+ "select() returned %d without reason!! return_time %d, curr_time %d",
+ selected, return_time, bmx_time );
+
+ goto loop4Event;
+ }
+
+ // check for changed interface status...
+ if ( FD_ISSET( ifevent_sk, &tmp_wait_set ) ) {
+
+ dbg_mute( 40, DBGL_CHANGES, DBGT_INFO,
+ "select() indicated changed interface status! Going to check
interfaces!" );
+
+ recv_ifevent_netlink_sk( );
+
+ //do NOT delay checking of interfaces to not miss ifdown/up of interfaces !!
+ dev_check();
+
+ goto wait4Event_end;
+ }
+
+
+ // check for received packets...
+ struct avl_node *it = NULL;
+ while ((pb.iif = avl_iterate_item(&dev_ip4_tree, &it))) {
+
+ if ( pb.iif->linklayer == VAL_DEV_LL_LO )
+ continue;
+
+ if ( FD_ISSET( pb.iif->netwbrc_sock, &tmp_wait_set ) ) {
+
+ pb.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 );
+
+ if ( pb.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN )
) {
+
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "sock returned %d errno %d: %s",
+ pb.total_length, errno, strerror(errno) );
+
+ continue;
+ }
+
+ ioctl(pb.iif->netwbrc_sock, SIOCGSTAMP, &(pb.tv_stamp)) ;
+
+ rx_packet( &pb );
+
+ if ( --selected == 0 )
+ goto loop4Event;
+
+ }
+
+ if ( FD_ISSET( pb.iif->fullbrc_sock, &tmp_wait_set ) ) {
+
+ pb.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 );
+
+ if ( pb.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN )
) {
+
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "sock returned %d errno %d: %s",
+ pb.total_length, errno, strerror(errno) );
+
+ continue;
+ }
+
+ ioctl(pb.iif->fullbrc_sock, SIOCGSTAMP, &(pb.tv_stamp)) ;
+
+ rx_packet( &pb );
+
+ if ( --selected == 0 )
+ goto loop4Event;
+
+ }
+
+
+ if ( FD_ISSET( pb.iif->unicast_sock, &tmp_wait_set ) ) {
+
+ pb.unicast = YES;
+
+ struct msghdr msghdr;
+ struct iovec iovec;
+ char buf[4096];
+ struct cmsghdr *cp;
+ struct timeval *tv_stamp = NULL;
+
+ iovec.iov_base = pb.packet_in;
+ iovec.iov_len = sizeof(pb.packet_in) - 1;
+
+ msghdr.msg_name = (struct sockaddr *)&pb.addr;
+ msghdr.msg_namelen = addr_len;
+ msghdr.msg_iov = &iovec;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_control = buf;
+ msghdr.msg_controllen = sizeof( buf );
+ msghdr.msg_flags = 0;
+
+ errno=0;
+
+ pb.total_length = recvmsg( pb.iif->unicast_sock, &msghdr, MSG_DONTWAIT );
+
+ if ( pb.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN )
) {
+ dbgf(DBGL_SYS, DBGT_WARN,
+ "sock returned %d errno %d: %s",
+ pb.total_length, errno, strerror(errno) );
+ continue;
+ }
+
+#ifdef SO_TIMESTAMP
+ for (cp = CMSG_FIRSTHDR(&msghdr); cp; cp = CMSG_NXTHDR(&msghdr, cp)) {
+
+ if ( cp->cmsg_type == SO_TIMESTAMP &&
+ cp->cmsg_level == SOL_SOCKET &&
+ cp->cmsg_len >= CMSG_LEN(sizeof(struct timeval)) ) {
+
+ tv_stamp = (struct timeval*)CMSG_DATA(cp);
+ break;
+ }
+ }
+#endif
+ if ( tv_stamp == NULL )
+ ioctl( pb.iif->unicast_sock, SIOCGSTAMP, &(pb.tv_stamp) );
+ else
+ timercpy( tv_stamp, &(pb.tv_stamp) );
+
+ rx_packet( &pb );
+
+ if ( --selected == 0)
+ goto loop4Event;
+ //goto wait4Event_end;
+
+ }
+
+ }
+
+loop4ActivePlugins:
+
+ // check active plugins...
+ list_for_each( list_pos, &cb_fd_list ) {
+
+ struct cb_fd_node *cdn = list_entry( list_pos, struct cb_fd_node, list );
+
+ if ( FD_ISSET( cdn->fd, &tmp_wait_set ) ) {
+
+ FD_CLR( cdn->fd, &tmp_wait_set );
+
+ (*(cdn->cb_fd_handler)) (cdn->fd);
+
+ // list might have changed, due to unregistered handlers, reiterate NOW
+ //TBD: check if fd was really consumed !
+ if ( --selected == 0 )
+ goto loop4Event;
+ //goto wait4Event_end;
+
+ goto loop4ActivePlugins;
+ }
+
+ }
+
+
+ // check for new control clients...
+ if ( FD_ISSET( unix_sock, &tmp_wait_set ) ) {
+
+ dbgf_all( DBGT_INFO, "new control client..." );
+
+ accept_ctrl_node();
+
+ if ( --selected == 0 )
+ goto loop4Event;
+
+ //goto wait4Event_end;
+ }
+
+
+loop4ActiveClients:
+ // check for all connected control clients...
+ list_for_each( list_pos, &ctrl_list ) {
+
+ struct ctrl_node *client = list_entry( list_pos, struct ctrl_node, list );
+
+ if ( FD_ISSET( client->fd, &tmp_wait_set ) ) {
+
+ FD_CLR( client->fd, &tmp_wait_set );
+
+ //omit debugging here since event could be a closed -d4 ctrl socket
+ //which should be removed before debugging
+ //dbgf_all( DBGT_INFO, "got msg from control client");
+
+ handle_ctrl_node( client );
+
+ --selected;
+
+ // return straight because client might be removed and list might have changed.
+ goto loop4ActiveClients;
+ }
+
+ }
+
+
+
+ if ( selected )
+ dbg( DBGL_CHANGES, DBGT_WARN,
+ "select() returned with %d unhandled event(s)!! return_time %d, curr_time
%d",
+ selected, return_time, bmx_time );
+
+ break;
+ }
+
+wait4Event_end:
+
+ dbgf_all( DBGT_INFO, "end of function");
+
+ return;
+}
+
+
+
+
+
+static struct opt_type schedule_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, "\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 ) );
+}
+
+
+
+void cleanup_schedule( void ) {
+
+
+ struct task_node *tn;
+
+ 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();
+}
Added: trunk/bmx/schedule.h
===================================================================
--- trunk/bmx/schedule.h (rev 0)
+++ trunk/bmx/schedule.h 2010-06-03 20:07:47 UTC (rev 1683)
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+
+
+void init_schedule( void );
+void change_selects( void );
+void cleanup_schedule( void );
+void register_task( uint32_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 );
+