Intermediate step for unification
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Thu, 6 Nov 2014 12:03:31 +0000 (13:03 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Thu, 6 Nov 2014 12:03:31 +0000 (13:03 +0100)
208 files changed:
CMakeLists.txt
cmake/OONFBuildLibrary.cmake
cmake/app_config.cmake [new file with mode: 0644]
cmake/link_app_dynamic.cmake [new file with mode: 0644]
cmake/link_app_static.cmake [new file with mode: 0644]
cmake/prepare_app.cmake [new file with mode: 0644]
src-api/CMakeLists.txt
src-api/core/CMakeLists.txt
src-api/core/oonf_cfg.c
src-api/core/oonf_cfg.h
src-api/core/oonf_logging.c
src-api/core/oonf_logging.h
src-api/core/oonf_main.c [new file with mode: 0644]
src-api/core/oonf_main.h [new file with mode: 0644]
src-api/core/oonf_plugins.c [deleted file]
src-api/core/oonf_subsystem.c
src-api/core/oonf_subsystem.h
src-api/subsystems/oonf_class.c
src-api/subsystems/oonf_class.h
src-api/subsystems/oonf_clock.c
src-api/subsystems/oonf_clock.h
src-api/subsystems/oonf_duplicate_set.c
src-api/subsystems/oonf_duplicate_set.h
src-api/subsystems/oonf_http.c
src-api/subsystems/oonf_http.h
src-api/subsystems/oonf_interface.c
src-api/subsystems/oonf_interface.h
src-api/subsystems/oonf_layer2.c
src-api/subsystems/oonf_layer2.h
src-api/subsystems/oonf_packet_socket.c
src-api/subsystems/oonf_packet_socket.h
src-api/subsystems/oonf_rfc5444.c
src-api/subsystems/oonf_rfc5444.h
src-api/subsystems/oonf_socket.c
src-api/subsystems/oonf_socket.h
src-api/subsystems/oonf_stream_socket.c
src-api/subsystems/oonf_stream_socket.h
src-api/subsystems/oonf_telnet.c
src-api/subsystems/oonf_telnet.h
src-api/subsystems/oonf_timer.c
src-api/subsystems/oonf_timer.h
src-api/subsystems/oonf_viewer.c
src-api/subsystems/oonf_viewer.h
src-api/subsystems/os_clock.h
src-api/subsystems/os_linux/os_clock_linux.c
src-api/subsystems/os_linux/os_net_linux.c
src-api/subsystems/os_linux/os_routing_linux.c
src-api/subsystems/os_linux/os_system_linux.c
src-api/subsystems/os_net.h
src-api/subsystems/os_routing.h
src-api/subsystems/os_system.h
src-plugins/CMakeLists.txt
src-plugins/generic/CMakeLists.txt [new file with mode: 0644]
src-plugins/generic/cfg_compact/CMakeLists.txt [moved from src-plugins/cfg_compact/CMakeLists.txt with 100% similarity]
src-plugins/generic/cfg_compact/README_CFG_COMPACT [moved from src-plugins/cfg_compact/README_CFG_COMPACT with 100% similarity]
src-plugins/generic/cfg_compact/cfg_compact.c [moved from src-plugins/cfg_compact/cfg_compact.c with 99% similarity]
src-plugins/generic/cfg_compact/cfg_compact.h [moved from src-plugins/cfg_compact/cfg_compact.h with 97% similarity]
src-plugins/generic/cfg_uciloader/CMakeLists.txt [moved from src-plugins/cfg_uciloader/CMakeLists.txt with 100% similarity]
src-plugins/generic/cfg_uciloader/cfg_uciloader.c [moved from src-plugins/cfg_uciloader/cfg_uciloader.c with 99% similarity]
src-plugins/generic/cfg_uciloader/cfg_uciloader.h [moved from src-plugins/cfg_uciloader/cfg_uciloader.h with 97% similarity]
src-plugins/generic/dlep/CMakeLists.txt [moved from src-plugins/dlep/CMakeLists.txt with 100% similarity]
src-plugins/generic/dlep/README_DLEP_RADIO [moved from src-plugins/dlep/README_DLEP_RADIO with 100% similarity]
src-plugins/generic/dlep/README_DLEP_ROUTER [moved from src-plugins/dlep/README_DLEP_ROUTER with 100% similarity]
src-plugins/generic/dlep/dlep_bitmap.c [moved from src-plugins/dlep/dlep_bitmap.c with 100% similarity]
src-plugins/generic/dlep/dlep_bitmap.h [moved from src-plugins/dlep/dlep_bitmap.h with 100% similarity]
src-plugins/generic/dlep/dlep_iana.h [moved from src-plugins/dlep/dlep_iana.h with 100% similarity]
src-plugins/generic/dlep/dlep_parser.c [moved from src-plugins/dlep/dlep_parser.c with 100% similarity]
src-plugins/generic/dlep/dlep_parser.h [moved from src-plugins/dlep/dlep_parser.h with 100% similarity]
src-plugins/generic/dlep/dlep_static_data.c [moved from src-plugins/dlep/dlep_static_data.c with 100% similarity]
src-plugins/generic/dlep/dlep_static_data.h [moved from src-plugins/dlep/dlep_static_data.h with 100% similarity]
src-plugins/generic/dlep/dlep_writer.c [moved from src-plugins/dlep/dlep_writer.c with 100% similarity]
src-plugins/generic/dlep/dlep_writer.h [moved from src-plugins/dlep/dlep_writer.h with 100% similarity]
src-plugins/generic/dlep/radio/dlep_radio.c [moved from src-plugins/dlep/radio/dlep_radio.c with 92% similarity]
src-plugins/generic/dlep/radio/dlep_radio.h [moved from src-plugins/dlep/radio/dlep_radio.h with 97% similarity]
src-plugins/generic/dlep/radio/dlep_radio_interface.c [moved from src-plugins/dlep/radio/dlep_radio_interface.c with 100% similarity]
src-plugins/generic/dlep/radio/dlep_radio_interface.h [moved from src-plugins/dlep/radio/dlep_radio_interface.h with 100% similarity]
src-plugins/generic/dlep/radio/dlep_radio_session.c [moved from src-plugins/dlep/radio/dlep_radio_session.c with 100% similarity]
src-plugins/generic/dlep/radio/dlep_radio_session.h [moved from src-plugins/dlep/radio/dlep_radio_session.h with 100% similarity]
src-plugins/generic/dlep/router/dlep_router.c [moved from src-plugins/dlep/router/dlep_router.c with 92% similarity]
src-plugins/generic/dlep/router/dlep_router.h [moved from src-plugins/dlep/router/dlep_router.h with 94% similarity]
src-plugins/generic/dlep/router/dlep_router_interface.c [moved from src-plugins/dlep/router/dlep_router_interface.c with 99% similarity]
src-plugins/generic/dlep/router/dlep_router_interface.h [moved from src-plugins/dlep/router/dlep_router_interface.h with 100% similarity]
src-plugins/generic/dlep/router/dlep_router_session.c [moved from src-plugins/dlep/router/dlep_router_session.c with 99% similarity]
src-plugins/generic/dlep/router/dlep_router_session.h [moved from src-plugins/dlep/router/dlep_router_session.h with 100% similarity]
src-plugins/generic/eth_listener/CMakeLists.txt [moved from src-plugins/eth_listener/CMakeLists.txt with 100% similarity]
src-plugins/generic/eth_listener/eth_listener.c [moved from src-plugins/eth_listener/eth_listener.c with 93% similarity]
src-plugins/generic/eth_listener/eth_listener.h [moved from src-plugins/eth_listener/eth_listener.h with 97% similarity]
src-plugins/generic/eth_listener/ethtool-copy.h [moved from src-plugins/eth_listener/ethtool-copy.h with 100% similarity]
src-plugins/generic/httptelnet/CMakeLists.txt [moved from src-plugins/httptelnet/CMakeLists.txt with 100% similarity]
src-plugins/generic/httptelnet/README_HTTPTELNET [moved from src-plugins/httptelnet/README_HTTPTELNET with 100% similarity]
src-plugins/generic/httptelnet/httptelnet.c [moved from src-plugins/httptelnet/httptelnet.c with 95% similarity]
src-plugins/generic/httptelnet/httptelnet.h [moved from src-plugins/httptelnet/httptelnet.h with 97% similarity]
src-plugins/generic/layer2_generator/CMakeLists.txt [moved from src-plugins/layer2_generator/CMakeLists.txt with 100% similarity]
src-plugins/generic/layer2_generator/layer2_generator.c [moved from src-plugins/layer2_generator/layer2_generator.c with 95% similarity]
src-plugins/generic/layer2_generator/layer2_generator.h [moved from src-plugins/layer2_generator/layer2_generator.h with 97% similarity]
src-plugins/generic/layer2info/CMakeLists.txt [moved from src-plugins/layer2info/CMakeLists.txt with 100% similarity]
src-plugins/generic/layer2info/layer2info.c [moved from src-plugins/layer2info/layer2info.c with 96% similarity]
src-plugins/generic/layer2info/layer2info.h [moved from src-plugins/layer2info/layer2info.h with 97% similarity]
src-plugins/generic/link_config/CMakeLists.txt [moved from src-plugins/link_config/CMakeLists.txt with 100% similarity]
src-plugins/generic/link_config/link_config.c [moved from src-plugins/link_config/link_config.c with 97% similarity]
src-plugins/generic/link_config/link_config.h [moved from src-plugins/link_config/link_config.h with 97% similarity]
src-plugins/generic/nl80211_listener/CMakeLists.txt [moved from src-plugins/nl80211_listener/CMakeLists.txt with 100% similarity]
src-plugins/generic/nl80211_listener/genl_get_family.c [moved from src-plugins/nl80211_listener/genl_get_family.c with 100% similarity]
src-plugins/generic/nl80211_listener/genl_get_family.h [moved from src-plugins/nl80211_listener/genl_get_family.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211.h [moved from src-plugins/nl80211_listener/nl80211.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_interface.c [moved from src-plugins/nl80211_listener/nl80211_get_interface.c with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_interface.h [moved from src-plugins/nl80211_listener/nl80211_get_interface.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_mpp.c [moved from src-plugins/nl80211_listener/nl80211_get_mpp.c with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_mpp.h [moved from src-plugins/nl80211_listener/nl80211_get_mpp.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_station_dump.c [moved from src-plugins/nl80211_listener/nl80211_get_station_dump.c with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_station_dump.h [moved from src-plugins/nl80211_listener/nl80211_get_station_dump.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_survey.c [moved from src-plugins/nl80211_listener/nl80211_get_survey.c with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_survey.h [moved from src-plugins/nl80211_listener/nl80211_get_survey.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_wiphy.c [moved from src-plugins/nl80211_listener/nl80211_get_wiphy.c with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_get_wiphy.h [moved from src-plugins/nl80211_listener/nl80211_get_wiphy.h with 100% similarity]
src-plugins/generic/nl80211_listener/nl80211_listener.c [moved from src-plugins/nl80211_listener/nl80211_listener.c with 97% similarity]
src-plugins/generic/nl80211_listener/nl80211_listener.h [moved from src-plugins/nl80211_listener/nl80211_listener.h with 98% similarity]
src-plugins/generic/nl80211_listener/scan_strategy.txt [moved from src-plugins/nl80211_listener/scan_strategy.txt with 100% similarity]
src-plugins/generic/plugin_controller/CMakeLists.txt [moved from src-plugins/plugin_controller/CMakeLists.txt with 100% similarity]
src-plugins/generic/plugin_controller/plugin_controller.c [moved from src-plugins/plugin_controller/plugin_controller.c with 96% similarity]
src-plugins/generic/plugin_controller/plugin_controller.h [moved from src-plugins/plugin_controller/plugin_controller.h with 97% similarity]
src-plugins/generic/remotecontrol/CMakeLists.txt [moved from src-plugins/remotecontrol/CMakeLists.txt with 100% similarity]
src-plugins/generic/remotecontrol/README_REMOTECONTROL [moved from src-plugins/remotecontrol/README_REMOTECONTROL with 100% similarity]
src-plugins/generic/remotecontrol/remotecontrol.c [moved from src-plugins/remotecontrol/remotecontrol.c with 98% similarity]
src-plugins/generic/remotecontrol/remotecontrol.h [moved from src-plugins/remotecontrol/remotecontrol.h with 97% similarity]
src-plugins/nhdp/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/auto_ll4/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/auto_ll4/auto_ll4.c [new file with mode: 0644]
src-plugins/nhdp/auto_ll4/auto_ll4.h [new file with mode: 0644]
src-plugins/nhdp/constant_metric/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/constant_metric/constant_metric.c [new file with mode: 0644]
src-plugins/nhdp/constant_metric/constant_metric.h [new file with mode: 0644]
src-plugins/nhdp/ff_dat_metric/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/ff_dat_metric/README_FF_DAT_METRIC [new file with mode: 0644]
src-plugins/nhdp/ff_dat_metric/ff_dat_metric.c [new file with mode: 0644]
src-plugins/nhdp/ff_dat_metric/ff_dat_metric.h [new file with mode: 0644]
src-plugins/nhdp/ff_ett_metric/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/ff_ett_metric/README_FF_ETT_METRIC [new file with mode: 0644]
src-plugins/nhdp/ff_ett_metric/ff_ett_metric.c [new file with mode: 0644]
src-plugins/nhdp/ff_ett_metric/ff_ett_metric.h [moved from src-api/core/oonf_plugins.h with 51% similarity]
src-plugins/nhdp/hysteresis_olsrv1/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/hysteresis_olsrv1/README_HYSTERESIS_OLSRV1 [new file with mode: 0644]
src-plugins/nhdp/hysteresis_olsrv1/hysteresis_olsrv1.c [new file with mode: 0644]
src-plugins/nhdp/hysteresis_olsrv1/hysteresis_olsrv1.h [new file with mode: 0644]
src-plugins/nhdp/mpr/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/mpr/mpr.c [new file with mode: 0644]
src-plugins/nhdp/mpr/mpr.h [new file with mode: 0644]
src-plugins/nhdp/mpr/neighbor-graph-flooding.c [new file with mode: 0644]
src-plugins/nhdp/mpr/neighbor-graph-flooding.h [new file with mode: 0644]
src-plugins/nhdp/mpr/neighbor-graph-routing.c [new file with mode: 0644]
src-plugins/nhdp/mpr/neighbor-graph-routing.h [new file with mode: 0644]
src-plugins/nhdp/mpr/neighbor-graph.c [new file with mode: 0644]
src-plugins/nhdp/mpr/neighbor-graph.h [new file with mode: 0644]
src-plugins/nhdp/mpr/selection-rfc7181.c [new file with mode: 0644]
src-plugins/nhdp/mpr/selection-rfc7181.h [new file with mode: 0644]
src-plugins/nhdp/neighbor_probing/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/neighbor_probing/README_NEIGHBOR_PROBING [new file with mode: 0644]
src-plugins/nhdp/neighbor_probing/neighbor_probing.c [new file with mode: 0644]
src-plugins/nhdp/neighbor_probing/neighbor_probing.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_db.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_db.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_domain.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_domain.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_hysteresis.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_hysteresis.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_interfaces.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_interfaces.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_reader.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_reader.h [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_writer.c [new file with mode: 0644]
src-plugins/nhdp/nhdp/nhdp_writer.h [new file with mode: 0644]
src-plugins/nhdp/nhdpcheck/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/nhdpcheck/README_NHDPCHECK [new file with mode: 0644]
src-plugins/nhdp/nhdpcheck/nhdpcheck.c [new file with mode: 0644]
src-plugins/nhdp/nhdpcheck/nhdpcheck.h [new file with mode: 0644]
src-plugins/nhdp/nhdpinfo/CMakeLists.txt [new file with mode: 0644]
src-plugins/nhdp/nhdpinfo/nhdpinfo.c [new file with mode: 0644]
src-plugins/nhdp/nhdpinfo/nhdpinfo.h [new file with mode: 0644]
src-plugins/olsrv2/CMakeLists.txt [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/CMakeLists.txt [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_lan.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_lan.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_originator.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_originator.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_reader.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_reader.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_routing.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_routing.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_tc.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_tc.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_writer.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2/olsrv2_writer.h [new file with mode: 0644]
src-plugins/olsrv2/olsrv2info/CMakeLists.txt [new file with mode: 0644]
src-plugins/olsrv2/olsrv2info/olsrv2info.c [new file with mode: 0644]
src-plugins/olsrv2/olsrv2info/olsrv2info.h [new file with mode: 0644]
src-plugins/olsrv2/route_modifier/CMakeLists.txt [new file with mode: 0644]
src-plugins/olsrv2/route_modifier/README_ROUTE_MODIFIER [new file with mode: 0644]
src-plugins/olsrv2/route_modifier/route_modifier.c [new file with mode: 0644]
src-plugins/olsrv2/route_modifier/route_modifier.h [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/app_data.c.in [new file with mode: 0644]
src/app_data.h.in [new file with mode: 0644]
src/main.c [new file with mode: 0644]

index c8f0da5..6a26d66 100644 (file)
@@ -7,6 +7,7 @@ cmake_minimum_required(VERSION 2.8.5 FATAL_ERROR)
 
 # set cached variables
 include (./cmake/lib_config.cmake)
+include (./cmake/app_config.cmake)
 
 # include compiler flags
 include (./cmake/cc_flags.cmake)
@@ -47,7 +48,6 @@ include (cmake/OONFBuildLibrary.cmake)
 include_directories(${PROJECT_BINARY_DIR})
 include_directories(external)
 include_directories(src-api)
-include_directories(src-plugins)
 
 if (NOT OONF_NO_TESTING)
     ENABLE_TESTING()
@@ -58,6 +58,7 @@ add_subdirectory(src-api)
 add_subdirectory(src-plugins)
 add_subdirectory(external)
 add_subdirectory(examples)
+add_subdirectory(src)
 
 get_property (targets GLOBAL PROPERTY OONF_TARGETS)
 export (TARGETS ${targets} FILE "${PROJECT_BINARY_DIR}/OONFLibraryDepends_api.cmake")
index c57f579..3dcbc78 100644 (file)
@@ -1,6 +1,6 @@
 # generic oonf library creation
 
-function (oonf_internal_create_plugin prefix libname source include link_internal linkto_external version)
+function (oonf_internal_create_plugin prefix libname source include link_internal linkto_external)
     add_library(${prefix}_${libname} SHARED ${source})
     add_library(${prefix}_static_${libname} STATIC ${source})
 
@@ -8,7 +8,7 @@ function (oonf_internal_create_plugin prefix libname source include link_interna
         target_link_libraries(${prefix}_${libname} ws2_32 iphlpapi)
     endif(WIN32)
 
-    set_target_properties(${prefix}_${libname} PROPERTIES SOVERSION ${version})
+    set_target_properties(${prefix}_${libname} PROPERTIES SOVERSION "${OONF_VERSION}")
 
     if (linkto_internal)
         target_link_libraries(${prefix}_${libname} ${linkto_internal})
@@ -32,7 +32,7 @@ function (oonf_internal_create_plugin prefix libname source include link_interna
 endfunction (oonf_internal_create_plugin)
 
 function (oonf_create_library libname source include linkto_internal linkto_external)
-    oonf_internal_create_plugin("oonf" "${libname}" "${source}" "${include}" "${linkto_internal}" "${linkto_external}" "${OONF_VERSION}")
+    oonf_internal_create_plugin("oonf" "${libname}" "${source}" "${include}" "${linkto_internal}" "${linkto_external}")
     
     install (TARGETS oonf_${libname}
         # IMPORTANT: Add the library to the "export-set"
@@ -58,7 +58,7 @@ endfunction (oonf_create_library)
 function (oonf_create_plugin libname source linkto_external)
     SET (linkto_internal oonf_subsystems oonf_core oonf_config oonf_rfc5444 oonf_common)
     
-    oonf_create_library("${libname}" "${source}" "" "${linkto_internal}" "${linkto_external}" "${OONF_VERSION}")
+    oonf_create_library("${libname}" "${source}" "" "${linkto_internal}" "${linkto_external}")
     
     set_source_files_properties(${source} PROPERTIES COMPILE_FLAGS "-DPLUGIN_FULLNAME=${libname}")
 endfunction (oonf_create_plugin)
@@ -66,7 +66,7 @@ endfunction (oonf_create_plugin)
 function (oonf_create_app_plugin libname source linkto_external)
     SET (linkto_internal oonf_subsystems oonf_core oonf_config oonf_rfc5444 oonf_common)
     
-    oonf_internal_create_plugin("${OONF_APP_LIBPREFIX}" "${libname}" "${source}" "" "${linkto_internal}" "${linkto_external}" "${OONF_APP_VERSION}")
+    oonf_internal_create_plugin("${OONF_APP_LIBPREFIX}" "${libname}" "${source}" "" "${linkto_internal}" "${linkto_external}")
     
     set_source_files_properties(${source} PROPERTIES COMPILE_FLAGS "-DPLUGIN_FULLNAME=${libname}")
     
diff --git a/cmake/app_config.cmake b/cmake/app_config.cmake
new file mode 100644 (file)
index 0000000..e3b3c5d
--- /dev/null
@@ -0,0 +1,54 @@
+###########################
+#### API configuration ####
+###########################
+
+# remove help texts from application, core-api and plugins
+set (OONF_REMOVE_HELPTEXT false CACHE BOOL
+     "Set if you want to remove the help texts from application to reduce size")
+
+# name of default configuration handler
+set (OONF_APP_DEFAULT_CFG_HANDLER Compact CACHE STRING
+     "Name of default configuration handler")
+
+###########################################
+#### Default Application configuration ####
+###########################################
+
+# set name of program the executable and library prefix
+set (OONF_APP OLSRd2)
+set (OONF_EXE olsrd2)
+
+# set Application library prefix
+set (OONF_APP_LIBPREFIX "olsrd2")
+
+# setup custom text before and after default help message
+set (OONF_HELP_PREFIX "OLSRv2 routing agent\\\\n")
+set (OONF_HELP_SUFFIX "")
+
+# setup custom text after version string
+set (OONF_VERSION_TRAILER "Visit http://www.olsr.org\\\\n")
+
+# set static plugins (list of plugin names, separated by space)
+set (OONF_CUSTOM_STATIC_PLUGINS "" CACHE STRING
+     "Space separated list of plugins to compile into application")
+
+# choose if framework should be linked static or dynamic
+set (OONF_FRAMEWORD_DYNAMIC false CACHE BOOL
+     "Compile the application with dynamic libraries instead of linking everything static")
+
+# set to true to stop application running without root privileges (true/false)
+set (OONF_NEED_ROOT true)
+
+# set to true to link packetbb API to application
+set (OONF_NEED_PACKETBB true)
+
+##############################
+#### Handle default cases ####
+##############################
+
+# use default static plugins if custom variable not set
+IF (NOT OONF_CUSTOM_STATIC_PLUGINS OR OONF_CUSTOM_STATIC_PLUGINS STREQUAL "")
+       set (OONF_STATIC_PLUGINS "cfg_compact nl80211_listener layer2info dlep_router")
+ELSE ()
+       set (OONF_STATIC_PLUGINS "${OONF_CUSTOM_STATIC_PLUGINS}")
+ENDIF ()
diff --git a/cmake/link_app_dynamic.cmake b/cmake/link_app_dynamic.cmake
new file mode 100644 (file)
index 0000000..1a3cd96
--- /dev/null
@@ -0,0 +1,41 @@
+# link static plugins
+string(REPLACE " " ";" PLUGIN_LIST "${OONF_STATIC_PLUGINS}")
+message ("Compiling project with dynamic libraries")
+message ("Static plugins: ${PLUGIN_LIST}")
+FOREACH(plugin ${PLUGIN_LIST})
+    IF(TARGET oonf_static_${plugin})
+        message ("    Found target: oonf_static_${plugin}")  
+        TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_${plugin} -Wl,--no-whole-archive)
+    ELSEIF (TARGET ${OONF_APP_LIBPREFIX}_static_${plugin})
+        message ("    Found target: ${OONF_APP_LIBPREFIX}_static_${plugin}")  
+        TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive ${OONF_APP_LIBPREFIX}_static_${plugin} -Wl,--no-whole-archive)
+    ELSE (TARGET oonf_static_${plugin})
+        message (FATAL_ERROR "    Did not found target: oonf_static_${plugin} or ${OONF_APP_LIBPREFIX}_static_${plugin}")
+    ENDIF(TARGET oonf_static_${plugin})
+ENDFOREACH(plugin)
+
+# link subsystems
+TARGET_LINK_LIBRARIES(${OONF_EXE} oonf_subsystems)
+
+# link core
+TARGET_LINK_LIBRARIES(${OONF_EXE} oonf_core)
+
+# link packetbb if necessary
+IF(OONF_NEED_PACKETBB)
+    TARGET_LINK_LIBRARIES(${OONF_EXE} oonf_rfc5444)
+ENDIF(OONF_NEED_PACKETBB)
+
+# link config and common API
+TARGET_LINK_LIBRARIES(${OONF_EXE} oonf_config)
+TARGET_LINK_LIBRARIES(${OONF_EXE} oonf_common)
+
+# link dlopen() library
+TARGET_LINK_LIBRARIES(${OONF_EXE} ${CMAKE_DL_LIBS})
+
+# link extra win32 libs
+IF(WIN32)
+    TARGET_LINK_LIBRARIES(${OONF_EXE} oonf_regex)
+
+    SET_TARGET_PROPERTIES(${OONF_EXE} PROPERTIES ENABLE_EXPORTS true)
+    TARGET_LINK_LIBRARIES(${OONF_EXE} ws2_32 iphlpapi)
+ENDIF(WIN32)
diff --git a/cmake/link_app_static.cmake b/cmake/link_app_static.cmake
new file mode 100644 (file)
index 0000000..8988fb3
--- /dev/null
@@ -0,0 +1,45 @@
+# the order of static libraries is important
+# earlier libraries can use the functions of later, not the
+# other way around
+
+# link static plugins
+message ("Compiling project with static libraries")
+message ("Static plugins: ${PLUGIN_LIST}")
+string(REPLACE " " ";" PLUGIN_LIST "${OONF_STATIC_PLUGINS}")
+FOREACH(plugin ${PLUGIN_LIST})
+    IF(TARGET oonf_static_${plugin})
+        message ("    Found target: oonf_static_${plugin}")  
+        TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_${plugin} -Wl,--no-whole-archive)
+    ELSEIF (TARGET ${OONF_APP_LIBPREFIX}_static_${plugin})
+        message ("    Found target: ${OONF_APP_LIBPREFIX}_static_${plugin}")  
+        TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive ${OONF_APP_LIBPREFIX}_static_${plugin} -Wl,--no-whole-archive)
+    ELSE (TARGET oonf_static_${plugin})
+        message (FATAL_ERROR "    Did not found target: oonf_static_${plugin} or ${OONF_APP_LIBPREFIX}_static_${plugin}")
+    ENDIF(TARGET oonf_static_${plugin})
+ENDFOREACH(plugin)
+
+# link subsystems
+TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_subsystems -Wl,--no-whole-archive)
+
+# link core
+TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_core -Wl,--no-whole-archive)
+
+# link packetbb if necessary
+IF(OONF_NEED_PACKETBB)
+    TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_rfc5444 -Wl,--no-whole-archive)
+ENDIF(OONF_NEED_PACKETBB)
+
+# link config and common API
+TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_config -Wl,--no-whole-archive)
+TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive oonf_static_common -Wl,--no-whole-archive)
+
+# link dlopen() library
+TARGET_LINK_LIBRARIES(${OONF_EXE} ${CMAKE_DL_LIBS})
+
+# link extra win32 libs
+IF(WIN32)
+    TARGET_LINK_LIBRARIES(${OONF_EXE} -Wl,--whole-archive static_regex -Wl,--no-whole-archive)
+
+    SET_TARGET_PROPERTIES(${OONF_EXE} PROPERTIES ENABLE_EXPORTS true)
+    TARGET_LINK_LIBRARIES(${OONF_EXE} ws2_32 iphlpapi)
+ENDIF(WIN32)
diff --git a/cmake/prepare_app.cmake b/cmake/prepare_app.cmake
new file mode 100644 (file)
index 0000000..ecb0ecb
--- /dev/null
@@ -0,0 +1,41 @@
+# create application data for including
+include_directories(${CMAKE_BINARY_DIR})
+
+# initialization for static plugins
+SET (GEN_DATA_C ${PROJECT_BINARY_DIR}/app_data.c)
+
+IF (NOT OONF_APP_DEFAULT_CFG_HANDLER)
+    SET (DEFAULT_CFG_HANDLER "NULL")
+ELSE (NOT OONF_APP_DEFAULT_CFG_HANDLER)
+    # use double quotes, one will be stripped away by the command call
+    SET (DEFAULT_CFG_HANDLER "\"\\\"${OONF_APP_DEFAULT_CFG_HANDLER}\\\"\"")
+ENDIF(NOT OONF_APP_DEFAULT_CFG_HANDLER)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/app_data.h.in ${PROJECT_BINARY_DIR}/app_data.h)
+
+ADD_CUSTOM_TARGET(AppCleanData ALL
+    COMMAND ${CMAKE_COMMAND} -E remove ${GEN_DATA_C}
+    COMMENT "Remove old builddata"
+)
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT ${GEN_DATA_C}
+    COMMAND ${CMAKE_COMMAND}
+        -DSRC=${CMAKE_CURRENT_SOURCE_DIR}/app_data.c.in
+        -DDST=${GEN_DATA_C}
+        -DGIT=${PROJECT_SOURCE_DIR}/.git
+        -DOONF_APP=${OONF_APP}
+        -DOONF_VERSION_TRAILER=${OONF_VERSION_TRAILER}
+        -DOONF_HELP_PREFIX=${OONF_HELP_PREFIX}
+        -DOONF_HELP_SUFFIX=${OONF_HELP_SUFFIX}
+        -DOONF_APP_DEFAULT_CFG_HANDLER=${DEFAULT_CFG_HANDLER}
+        -DOONF_APP_LIBPREFIX=${OONF_APP_LIBPREFIX}
+        -DCMAKE_SYSTEM=${CMAKE_SYSTEM}
+        -DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX}
+        -DCMAKE_SHARED_LIBRARY_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX}
+        -DOONF_APP_GIT=${OONF_APP_GIT}
+        -P ${PROJECT_SOURCE_DIR}/cmake/generate_builddata.cmake
+    DEPENDS AppCleanData
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    COMMENT "Create new builddata"
+)
index 988d933..4fc3d11 100644 (file)
@@ -1,6 +1,6 @@
 # build framework
 add_subdirectory(common)
 add_subdirectory(config)
-add_subdirectory(rfc5444)
 add_subdirectory(core)
+add_subdirectory(rfc5444)
 add_subdirectory(subsystems)
index f7b6de8..5fa24b2 100644 (file)
@@ -25,13 +25,14 @@ ADD_CUSTOM_COMMAND (
 SET(OONF_CORE_SRCS oonf_cfg.c
                    oonf_logging.c
                    oonf_logging_cfg.c
-                   oonf_plugins.c
+                   oonf_main.c
                    oonf_subsystem.c
                    ${GEN_DATA_C})
 
 SET(OONF_CORE_INCLUDES oonf_cfg.h
                        oonf_logging.h
                        oonf_logging_cfg.h
+                       oonf_main.h
                        oonf_plugins.h
                        oonf_subsystem.h
                        oonf_libdata.h
index 00474bb..d12e570 100644 (file)
@@ -48,7 +48,6 @@
 
 #include "core/oonf_cfg.h"
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
 #include "core/oonf_subsystem.h"
 
 /* global config */
@@ -270,6 +269,12 @@ oonf_cfg_loadplugins(void) {
     }
   }
 
+  /* initialize all plugins */
+  avl_for_each_element_safe(&oonf_plugin_tree, plugin, _node, plugin_it) {
+    if (oonf_plugins_call_init(plugin)) {
+      return -1;
+    }
+  }
   return 0;
 }
 
@@ -514,7 +519,7 @@ oonf_cfg_get_argc(void) {
 /**
  * @return argument vector of original main() function
  */
-const char **
+char **
 oonf_cfg_get_argv(void) {
-  return (const char **) _argv;
+  return _argv;
 }
index 2920666..f9f2209 100644 (file)
@@ -67,7 +67,8 @@ struct oonf_config_global {
 EXPORT extern struct oonf_subsystem oonf_cfg_subsystem;
 EXPORT extern struct oonf_config_global config_global;
 
-EXPORT int oonf_cfg_init(int argc, char **argv, const char *) __attribute__((warn_unused_result));
+EXPORT int oonf_cfg_init(int argc, char **argv,
+    const char *) __attribute__((warn_unused_result));
 EXPORT void oonf_cfg_cleanup(void);
 EXPORT int oonf_cfg_loadplugins(void) __attribute__((warn_unused_result));
 EXPORT struct oonf_subsystem *oonf_cfg_load_plugin(const char *name);
@@ -89,7 +90,7 @@ EXPORT struct cfg_db *oonf_cfg_get_rawdb(void);
 EXPORT struct cfg_schema *oonf_cfg_get_schema(void);
 
 EXPORT int oonf_cfg_get_argc(void);
-EXPORT const char **oonf_cfg_get_argv(void);
+EXPORT char **oonf_cfg_get_argv(void);
 
 /* do not use this in plugins */
 EXPORT int oonf_cfg_update_globalcfg(bool) __attribute__((warn_unused_result));
index 89ddd71..4a67bc5 100644 (file)
@@ -270,7 +270,7 @@ oonf_log_printversion(struct autobuf *abuf) {
   abuf_appendf(abuf," %s version %s\n"
             " Application commit: %s\n",
             _appdata->app_name,
-            _appdata->app_version,
+            _libdata->lib_version,
             _appdata->git_commit);
   abuf_appendf(abuf, " Library commit: %s\n", _libdata->git_commit);
   abuf_puts(abuf, _appdata->versionstring_trailer);
index fae13e4..865b0a9 100644 (file)
@@ -96,7 +96,6 @@ struct oonf_log_parameters {
 
 struct oonf_appdata {
   const char *app_name;
-  const char *app_version;
   const char *versionstring_trailer;
   const char *help_prefix;
   const char *help_suffix;
diff --git a/src-api/core/oonf_main.c b/src-api/core/oonf_main.c
new file mode 100644 (file)
index 0000000..07a97c9
--- /dev/null
@@ -0,0 +1,642 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/times.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "config/cfg_cmd.h"
+#include "config/cfg_db.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_cfg.h"
+#include "core/oonf_libdata.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_logging_cfg.h"
+#include "core/oonf_subsystem.h"
+#include "core/os_core.h"
+
+#include "core/oonf_main.h"
+
+/* prototypes */
+static int _write_pidfile(const char *);
+static void quit_signal_handler(int);
+static void hup_signal_handler(int);
+static void setup_signalhandler(void);
+static int mainloop(int argc, char **argv,
+    const struct oonf_appdata *);
+static void parse_early_commandline(int argc, char **argv);
+static int parse_commandline(int argc, char **argv,
+    const struct oonf_appdata *, bool reload_only);
+static int display_schema(void);
+
+static bool _end_oonf_signal, _display_schema, _debug_early, _ignore_unknown;
+static char *_schema_name;
+
+static int (*_handle_scheduling)(void) = NULL;
+
+enum argv_short_options {
+  argv_option_schema = 256,
+  argv_option_debug_early,
+  argv_option_ignore_unknown,
+};
+
+static struct option oonf_options[] = {
+#if !defined(REMOVE_HELPTEXT)
+  { "help",            no_argument,       0, 'h' },
+#endif
+  { "version",         no_argument,       0, 'v' },
+  { "plugin",          required_argument, 0, 'p' },
+  { "load",            required_argument, 0, 'l' },
+  { "save",            required_argument, 0, 'S' },
+  { "set",             required_argument, 0, 's' },
+  { "remove",          required_argument, 0, 'r' },
+  { "get",             optional_argument, 0, 'g' },
+  { "quit",            no_argument,       0, 'q' },
+  { "schema",          optional_argument, 0, argv_option_schema },
+  { "Xearlydebug",     no_argument,       0, argv_option_debug_early },
+  { "Xignoreunknown",  no_argument,       0, argv_option_ignore_unknown },
+  { NULL, 0,0,0 }
+};
+
+#if !defined(REMOVE_HELPTEXT)
+static const char *help_text =
+    "Mandatory arguments for long options are mandatory for short options too.\n"
+    "  -h, --help                             Display this help file\n"
+    "  -v, --version                          Display the version string and the included static plugins\n"
+    "  -p, --plugin=shared-library            Load a shared library as a plugin\n"
+    "  -q, --quit                             Load plugins and validate configuration, then end\n"
+    "      --schema                           Display all allowed section types of configuration\n"
+    "              =all                       Display all allowed entries in all sections\n"
+    "              =section_type              Display all allowed entries of one configuration section\n"
+    "              =section_type.key          Display help text for configuration entry\n"
+    "  -l, --load=SOURCE                      Load configuration from a SOURCE\n"
+    "  -S, --save=TARGET                      Save configuration to a TARGET\n"
+    "  -s, --set=section_type.                Add an unnamed section to the configuration\n"
+    "           =section_type.key=value       Add a key/value pair to an unnamed section\n"
+    "           =section_type[name].          Add a named section to the configuration\n"
+    "           =section_type[name].key=value Add a key/value pair to a named section\n"
+    "  -r, --remove=section_type.             Remove all sections of a certain type\n"
+    "              =section_type.key          Remove a key in an unnamed section\n"
+    "              =section_type[name].       Remove a named section\n"
+    "              =section_type[name].key    Remove a key in a named section\n"
+    "  -g, --get                              Show all section types in database\n"
+    "           =section_type.                Show all named sections of a certain type\n"
+    "           =section_type.key             Show the value(s) of a key in an unnamed section\n"
+    "           =section_type[name].key       Show the value(s) of a key in a named section\n"
+    "\n"
+    "Expert/Experimental arguments\n"
+    "  --Xearlydebug                          Activate debugging output before configuration could be parsed\n"
+    "  --Xignoreunknown                       Ignore unknown command line arguments\n"
+    "\n"
+    "The remainder of the parameters which are no arguments are handled as interface names.\n"
+;
+#endif
+
+/**
+ * Main program
+ */
+int
+oonf_main(int argc, char **argv, const struct oonf_appdata *appdata) {
+  int return_code;
+
+  /* early initialization */
+  return_code = 1;
+
+  _schema_name = NULL;
+  _display_schema = false;
+  _debug_early = false;
+  _ignore_unknown = false;
+
+  /* setup signal handler */
+  _end_oonf_signal = false;
+  setup_signalhandler();
+
+  /* parse "early" command line arguments */
+  parse_early_commandline(argc, argv);
+
+  /* initialize logger */
+  if (oonf_log_init(appdata, _debug_early ? LOG_SEVERITY_DEBUG : LOG_SEVERITY_WARN)) {
+    goto olsrd_cleanup;
+  }
+
+  /* prepare plugin initialization */
+  oonf_plugins_init();
+
+  /* initialize configuration system */
+  if (oonf_cfg_init(argc, argv, appdata->default_cfg_handler)) {
+    goto olsrd_cleanup;
+  }
+
+  /* add custom configuration definitions */
+  oonf_logcfg_init();
+
+  /* parse command line and read configuration files */
+  return_code = parse_commandline(argc, argv, appdata, false);
+  if (return_code != -1) {
+    /* end OONFd now */
+    goto olsrd_cleanup;
+  }
+
+  /* prepare for an error during initialization */
+  return_code = 1;
+
+  /* read global section early */
+  if (oonf_cfg_update_globalcfg(true)) {
+    OONF_WARN(LOG_MAIN, "Cannot read global configuration section");
+    goto olsrd_cleanup;
+  }
+
+  /* configure logger */
+  if (oonf_logcfg_apply(oonf_cfg_get_rawdb())) {
+    goto olsrd_cleanup;
+  }
+
+  /* load plugins */
+  if (oonf_cfg_loadplugins()) {
+    goto olsrd_cleanup;
+  }
+
+  /* show schema if necessary */
+  if (_display_schema) {
+    return_code = display_schema();
+    goto olsrd_cleanup;
+  }
+
+  /* check if we are root, otherwise stop */
+#if defined OONF_NEED_ROOT && OONF_NEED_ROOT == true
+  if (geteuid() != 0) {
+    OONF_WARN(LOG_MAIN, "You must be root(uid = 0) to run %s!\n",
+        oonf_appdata_get()->app_name);
+    goto olsrd_cleanup;
+  }
+#endif
+
+  if (config_global.lockfile != NULL && *config_global.lockfile != 0) {
+    /* create application lock */
+    if (os_core_create_lockfile(config_global.lockfile)) {
+      OONF_WARN(LOG_MAIN, "Could not acquire application lock '%s'",
+          config_global.lockfile);
+      goto olsrd_cleanup;
+    }
+  }
+
+  /* call initialization callbacks of dynamic plugins */
+  oonf_cfg_initplugins();
+
+  /* apply configuration */
+  if (oonf_cfg_apply()) {
+    goto olsrd_cleanup;
+  }
+
+  if (!oonf_cfg_is_running()) {
+    /*
+     * mayor error during late initialization
+     * or maybe the user decided otherwise and pressed CTRL-C
+     */
+    return_code = _end_oonf_signal ? 0 : 1;
+    goto olsrd_cleanup;
+  }
+
+  /* see if we need to fork */
+  if (config_global.fork && !_display_schema) {
+    /* tell main process that we are finished with initialization */
+    if (daemon(0,0) < 0) {
+      OONF_WARN(LOG_MAIN, "Could not fork into background: %s (%d)",
+          strerror(errno), errno);
+      goto olsrd_cleanup;
+    }
+
+    if (config_global.pidfile && *config_global.pidfile != 0) {
+      if (_write_pidfile(config_global.pidfile)) {
+        goto olsrd_cleanup;
+      }
+    }
+  }
+
+  /* activate mainloop */
+  return_code = mainloop(argc, argv, appdata);
+
+  /* tell plugins shutdown is in progress */
+  oonf_plugins_initiate_shutdown();
+
+  /* wait for 500 milliseconds and process socket events */
+  _handle_scheduling();
+#if 0
+  if (oonf_clock_update()) {
+    OONF_WARN(LOG_MAIN, "Clock update for shutdown failed");
+  }
+  next_interval = oonf_clock_get_absolute(500);
+  if (oonf_socket_handle(NULL, next_interval)) {
+    OONF_WARN(LOG_MAIN, "Grace period for shutdown failed.");
+  }
+#endif
+
+olsrd_cleanup:
+  /* free plugins */
+  oonf_cfg_unconfigure_plugins();
+  oonf_plugins_cleanup();
+
+  /* free logging/config bridge resources */
+  oonf_logcfg_cleanup();
+
+  /* free configuration resources */
+  oonf_cfg_cleanup();
+
+  /* free logger resources */
+  oonf_log_cleanup();
+
+  return return_code;
+}
+
+int
+oonf_main_set_scheduler(int (*scheduler)(void)) {
+  if (_handle_scheduling) {
+    return -1;
+  }
+
+  _handle_scheduling = scheduler;
+  return 0;
+}
+
+bool
+oonf_main_shall_stop_scheduler(void) {
+  return oonf_cfg_is_commit_set()
+        || oonf_cfg_is_reload_set()
+        || !oonf_cfg_is_running();
+}
+
+/**
+ * Write process ID into file
+ * @param filename
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_write_pidfile(const char *filename) {
+  int pid_fd;
+  char buffer[16];
+
+  pid_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
+      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+  if (pid_fd < 0) {
+    OONF_WARN(LOG_MAIN, "Could not open pidfile '%s': %s (%d)",
+        filename, strerror(errno), errno);
+    return -1;
+  }
+
+  snprintf(buffer, sizeof(buffer), "%d\n", getpid());
+
+  if (write(pid_fd, buffer, strlen(buffer)+1) < 0) {
+    OONF_WARN(LOG_MAIN, "Could not write pid %d into pidfile '%s': %s (%d)",
+        getpid(), filename, strerror(errno), errno);
+    close(pid_fd);
+    return -1;
+  }
+
+  close(pid_fd);
+  return 0;
+}
+
+/**
+ * Handle incoming SIGINT signal
+ * @param signo
+ */
+static void
+quit_signal_handler(int signo __attribute__ ((unused))) {
+  oonf_cfg_exit();
+}
+
+/**
+ * Handle incoming SIGHUP signal
+ * @param signo
+ */
+static void
+hup_signal_handler(int signo __attribute__ ((unused))) {
+  oonf_cfg_trigger_reload();
+}
+
+/**
+ * Mainloop of olsrd
+ * @return exit code for olsrd
+ */
+static int
+mainloop(int argc, char **argv, const struct oonf_appdata *appdata) {
+  int exit_code = 0;
+
+  OONF_INFO(LOG_MAIN, "Starting %s", appdata->app_name);
+
+  /* enter main loop */
+  while (oonf_cfg_is_running()) {
+    /* call event scheduler */
+    if (_handle_scheduling()) {
+      exit_code = 1;
+      break;
+    }
+#if 0
+    /*
+     * Update the global timestamp. We are using a non-wallclock timer here
+     * to avoid any undesired side effects if the system clock changes.
+     */
+    if (oonf_clock_update()) {
+      exit_code = 1;
+      break;
+    }
+
+    /* Read incoming data and handle it immediately */
+    if (oonf_socket_handle(_cb_stop_scheduler, 0)) {
+      exit_code = 1;
+      break;
+    }
+#endif
+
+    /* reload configuration if triggered */
+    if (oonf_cfg_is_reload_set()) {
+      OONF_INFO(LOG_MAIN, "Reloading configuration");
+      if (oonf_cfg_clear_rawdb()) {
+        break;
+      }
+      if (parse_commandline(argc, argv, appdata, true) == -1) {
+        if (oonf_cfg_apply()) {
+          break;
+        }
+      }
+    }
+
+    /* commit config if triggered */
+    if (oonf_cfg_is_commit_set()) {
+      OONF_INFO(LOG_MAIN, "Commiting configuration");
+      if (oonf_cfg_apply()) {
+        break;
+      }
+    }
+  }
+
+  OONF_INFO(LOG_MAIN, "Ending %s", appdata->app_name);
+  return exit_code;
+}
+
+/**
+ * Setup signal handling for olsrd
+ */
+static void
+setup_signalhandler(void) {
+  static struct sigaction act;
+
+  memset(&act, 0, sizeof(act));
+
+  /* setup signal handler first */
+  sigemptyset(&act.sa_mask);
+  act.sa_flags = 0;
+
+  act.sa_handler = quit_signal_handler;
+  sigaction(SIGINT, &act, NULL);
+  sigaction(SIGQUIT, &act, NULL);
+  sigaction(SIGILL, &act, NULL);
+  sigaction(SIGABRT, &act, NULL);
+  sigaction(SIGTERM, &act, NULL);
+
+  act.sa_handler = SIG_IGN;
+  sigaction(SIGPIPE, &act, NULL);
+  sigaction(SIGUSR1, &act, NULL);
+  sigaction(SIGUSR2, &act, NULL);
+
+  act.sa_handler = hup_signal_handler;
+  sigaction(SIGHUP, &act, NULL);
+}
+
+static void
+parse_early_commandline(int argc, char **argv) {
+  int opt, opt_idx;
+
+  opterr = 0;
+  while (0 <= (opt = getopt_long(argc, argv, "-", oonf_options, &opt_idx))) {
+    switch (opt) {
+      case argv_option_debug_early:
+        _debug_early = true;
+        break;
+      case argv_option_ignore_unknown:
+        _ignore_unknown = true;
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+/**
+ * Parse command line of olsrd
+ * @param argc number of arguments
+ * @param argv argument vector
+ * @param def_config default configuration file, NULL if
+ *   no default config file should be loaded
+ * @param reload_only true if only the command line arguments should
+ *   be parsed that load a configuration (--set, --remove, --load,
+ *   and --format), false for normal full parsing.
+ * @return -1 if olsrd should start normally, otherwise olsrd should
+ *   exit with the returned number
+ */
+static int
+parse_commandline(int argc, char **argv,
+    const struct oonf_appdata *appdata, bool reload_only) {
+  struct oonf_subsystem *plugin;
+  const char *parameters;
+  struct autobuf log;
+  struct cfg_db *db;
+  int opt, opt_idx, return_code;
+
+  return_code = -1;
+  db = oonf_cfg_get_rawdb();
+
+  /* reset getopt_long */
+  opt_idx = -1;
+  optind = 1;
+  opterr = _ignore_unknown ? 0 : -1;
+
+  abuf_init(&log);
+
+  if (reload_only) {
+    /* only parameters that load and change configuration data */
+    parameters = "-p:l:s:r:f:n";
+  }
+  else {
+    parameters = "-hvp:ql:S:s:r:g::f:n";
+  }
+
+  while (return_code == -1
+      && 0 <= (opt = getopt_long(argc, argv, parameters, oonf_options, &opt_idx))) {
+    switch (opt) {
+      case 'h':
+#if !defined(REMOVE_HELPTEXT)
+        abuf_appendf(&log, "Usage: %s [OPTION]...\n%s%s%s", argv[0],
+            appdata->help_prefix, help_text, appdata->help_suffix);
+#endif
+        return_code = 0;
+        break;
+
+      case argv_option_debug_early:
+      case argv_option_ignore_unknown:
+        /* ignore this here */
+        break;
+
+      case 'v':
+        oonf_log_printversion(&log);
+        avl_for_each_element(&oonf_plugin_tree, plugin, _node) {
+          if (!oonf_subsystem_is_dynamic(plugin)) {
+            abuf_appendf(&log, "Static plugin: %s\n", plugin->name);
+          }
+        }
+        return_code = 0;
+        break;
+      case 'p':
+        if (oonf_cfg_load_plugin(optarg) == NULL) {
+          return_code = 1;
+        }
+        else {
+          cfg_db_add_entry(oonf_cfg_get_rawdb(), CFG_SECTION_GLOBAL, NULL, CFG_GLOBAL_PLUGIN, optarg);
+        }
+        break;
+      case 'q':
+        oonf_cfg_exit();
+        break;
+
+      case argv_option_schema:
+        _schema_name = optarg;
+        _display_schema = true;
+        break;
+
+      case 'l':
+          if (cfg_cmd_handle_load(oonf_cfg_get_instance(), db, optarg, &log)) {
+            return_code = 1;
+          }
+          break;
+      case 'S':
+        if (cfg_cmd_handle_save(oonf_cfg_get_instance(), db, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 's':
+        if (cfg_cmd_handle_set(oonf_cfg_get_instance(), db, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 'r':
+        if (cfg_cmd_handle_remove(oonf_cfg_get_instance(), db, optarg, &log)) {
+          return_code = 1;
+        }
+        break;
+      case 'g':
+        if (cfg_cmd_handle_get(oonf_cfg_get_instance(), db, optarg, &log)) {
+          return_code = 1;
+        }
+        else {
+          return_code = 0;
+        }
+        break;
+      case 1:
+        /* ignore the rest of the parameters for now */
+#if 0
+        if (cfg_db_add_namedsection(db, CFG_INTERFACE_SECTION, optarg) == NULL) {
+          abuf_appendf(&log, "Could not add named section for interface %s", optarg);
+          return_code = 1;
+        }
+#endif
+        break;
+
+      default:
+        if (!(reload_only ||_ignore_unknown)) {
+          abuf_appendf(&log, "Unknown parameter: '%c' (%d)\n", opt, opt);
+          return_code = 1;
+        }
+        break;
+    }
+  }
+
+  while (return_code == -1 && optind < argc) {
+    optind++;
+  }
+
+  if (abuf_getlen(&log) > 0) {
+    if (reload_only) {
+      OONF_WARN(LOG_MAIN, "Cannot reload configuration.\n%s", abuf_getptr(&log));
+    }
+    else {
+      fputs(abuf_getptr(&log), return_code == 0 ? stdout : stderr);
+    }
+  }
+
+  abuf_free(&log);
+
+  return return_code;
+}
+
+/**
+ * Call the handle_schema command to give the user the schema of
+ * the configuration including plugins
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+display_schema(void) {
+  struct autobuf log;
+  int return_code;
+
+  return_code = 0;
+
+  abuf_init(&log);
+
+  if (cfg_cmd_handle_schema(oonf_cfg_get_rawdb(), _schema_name, &log)) {
+    return_code = -1;
+  }
+
+  if (abuf_getlen(&log) > 0) {
+    fputs(abuf_getptr(&log), stdout);
+  }
+
+  abuf_free(&log);
+
+  return return_code;
+}
diff --git a/src-api/core/oonf_main.h b/src-api/core/oonf_main.h
new file mode 100644 (file)
index 0000000..da79b14
--- /dev/null
@@ -0,0 +1,52 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef OONF_MAIN_H_
+#define OONF_MAIN_H_
+
+#include "common/common_types.h"
+#include "core/oonf_logging.h"
+
+EXPORT int oonf_main(int argc, char **argv, const struct oonf_appdata *);
+EXPORT int oonf_main_set_scheduler(int (*scheduler)(void));
+EXPORT bool oonf_main_shall_stop_scheduler(void);
+
+#endif /* OONF_MAIN_H_ */
diff --git a/src-api/core/oonf_plugins.c b/src-api/core/oonf_plugins.c
deleted file mode 100644 (file)
index 18003e7..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-
-/*
- * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
- * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in
- *   the documentation and/or other materials provided with the
- *   distribution.
- * * Neither the name of olsr.org, olsrd nor the names of its
- *   contributors may be used to endorse or promote products derived
- *   from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * Visit http://www.olsr.org for more information.
- *
- * If you find this software useful feel free to make a donation
- * to the project. For more information see the website or contact
- * the copyright holders.
- *
- */
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "common/autobuf.h"
-#include "common/list.h"
-#include "common/avl.h"
-#include "common/avl_comp.h"
-#include "common/template.h"
-
-#include "core/oonf_libdata.h"
-#include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
-
-/* constants */
-enum {
-  IDX_DLOPEN_LIB,
-  IDX_DLOPEN_PATH,
-  IDX_DLOPEN_PRE,
-  IDX_DLOPEN_PRELIB,
-  IDX_DLOPEN_POST,
-  IDX_DLOPEN_POSTLIB,
-  IDX_DLOPEN_VER,
-  IDX_DLOPEN_VERLIB,
-};
-
-/*
- * List of paths to look for plugins
- *
- * The elements of the patterns are:
- *
- * %LIB%:  name of the plugin
- * %PATH%: local path (linux: ".")
- *
- * %PRE%:  shared library prefix defined by the app (linux: "lib<app>_")
- * %POST%: shared library postfix defined by the app (linux: ".so")
- * %VER:   version number as defined by the app (e.g. "0.1.0")
- *
- * %PRELIB%: shared library prefix defined by the API (linux: "liboonf_")
- * %POST%:   shared library postfix defined by the app (linux: ".so")
- * %VER:     version number as defined by the app (e.g. "0.1.0")
- */
-static const char *DLOPEN_PATTERNS[] = {
-  "%PATH%/%PRE%%LIB%%POST%.%VER%",
-  "%PATH%/%PRELIB%%LIB%%POSTLIB%.%VERLIB%",
-  "%PATH%/%PRE%%LIB%%POST%",
-  "%PATH%/%PRELIB%%LIB%%POSTLIB%",
-  "%PRE%%LIB%%POST%.%VER%",
-  "%PRELIB%%LIB%%POSTLIB%.%VERLIB%",
-  "%PRE%%LIB%%POST%",
-  "%PRELIB%%LIB%%POSTLIB%",
-};
-
-/* Local functions */
-struct avl_tree oonf_plugin_tree;
-static bool _plugin_tree_initialized = false;
-
-/* library loading patterns */
-static struct abuf_template_data_entry _dlopen_data[] = {
-  [IDX_DLOPEN_LIB]     =  { .key = "LIB" },
-  [IDX_DLOPEN_PATH]    =  { .key = "PATH", .value = "." },
-  [IDX_DLOPEN_PRE]     =  { .key = "PRE" },
-  [IDX_DLOPEN_PRELIB]  =  { .key = "PRELIB" },
-  [IDX_DLOPEN_POST]    =  { .key = "POST" },
-  [IDX_DLOPEN_POSTLIB] =  { .key = "POSTLIB" },
-  [IDX_DLOPEN_VER]     =  { .key = "VER" },
-  [IDX_DLOPEN_VERLIB]  =  { .key = "VERLIB" },
-};
-
-static void _init_plugin_tree(void);
-static int _unload_plugin(struct oonf_subsystem *plugin, bool cleanup);
-static void *_open_plugin(const char *filename);
-
-/**
- * Initialize the plugin loader system
- */
-void
-oonf_plugins_init(void) {
-  _init_plugin_tree();
-
-  /* load predefined values for dlopen templates */
-  _dlopen_data[IDX_DLOPEN_PRE].value =
-      oonf_log_get_appdata()->sharedlibrary_prefix;
-  _dlopen_data[IDX_DLOPEN_POST].value =
-      oonf_log_get_appdata()->sharedlibrary_postfix;
-  _dlopen_data[IDX_DLOPEN_VER].value =
-      oonf_log_get_appdata()->app_version;
-
-  _dlopen_data[IDX_DLOPEN_PRELIB].value =
-      oonf_log_get_libdata()->sharedlibrary_prefix;
-  _dlopen_data[IDX_DLOPEN_POSTLIB].value =
-      oonf_log_get_libdata()->sharedlibrary_postfix;
-  _dlopen_data[IDX_DLOPEN_VERLIB].value =
-      oonf_log_get_libdata()->lib_version;
-}
-
-/**
- * Disable and unload all plugins
- */
-void
-oonf_plugins_cleanup(void) {
-  struct oonf_subsystem *plugin, *iterator;
-
-  avl_for_each_element_safe(&oonf_plugin_tree, plugin, _node, iterator) {
-    _unload_plugin(plugin, true);
-  }
-}
-
-/**
- * Sets the user-configured path to look for plugins
- * @param path default path
- */
-void
-oonf_plugins_set_path(const char *path) {
-  _dlopen_data[IDX_DLOPEN_PATH].value = path;
-}
-
-/**
- * Tell plugins to begin to shutdown
- */
-void
-oonf_plugins_initiate_shutdown(void) {
-  struct oonf_subsystem *plugin, *iterator;
-
-  avl_for_each_element_safe(&oonf_plugin_tree, plugin, _node, iterator) {
-    if (plugin->initiate_shutdown) {
-      plugin->initiate_shutdown();
-    }
-  }
-}
-
-/**
- * This function is called by the constructor of a plugin to
- * insert the plugin into the global list. It will be called before
- * any subsystem was initialized!
- * @param plugin pointer to plugin definition
- */
-void
-oonf_plugins_hook(struct oonf_subsystem *plugin) {
-  /* make sure plugin tree is initialized */
-  _init_plugin_tree();
-
-  /* check if plugin is already in tree */
-  if (oonf_plugins_get(plugin->name)) {
-    return;
-  }
-
-  /* hook plugin into avl tree */
-  plugin->_node.key = plugin->name;
-  avl_insert(&oonf_plugin_tree, &plugin->_node);
-}
-
-/**
- * Extracts the plugin name from a library name, including optional path,
- * prefix and/or postfix
- * @param libname library name
- * @return pointer to buffer with plugin name, must be freed later
- */
-void
-oonf_plugins_extract_name(
-    struct oonf_plugin_namebuf *pluginname, const char *libname) {
-  size_t start, end;
-  char *ptr;
-
-  memset(pluginname, 0, sizeof(*pluginname));
-
-  start = 0;
-  end = strlen(libname);
-
-  /* remove path */
-  if ((ptr = strrchr(libname, '/')) != NULL) {
-    start += (ptr - libname);
-  }
-  else if ((ptr = strrchr(libname, '\\')) != NULL) {
-    start += (ptr - libname);
-  }
-
-  /* remove (oonf/app) lib prefix */
-  if (str_startswith_nocase(&libname[start],
-      oonf_log_get_libdata()->sharedlibrary_prefix)) {
-    start += strlen(oonf_log_get_libdata()->sharedlibrary_prefix);
-  }
-  else if (str_startswith_nocase(&libname[start],
-      oonf_log_get_appdata()->sharedlibrary_prefix)) {
-    start += strlen(oonf_log_get_appdata()->sharedlibrary_prefix);
-  }
-
-  /* remove (oonf/app) lib postfix */
-  if (str_endswith_nocase(&libname[start],
-      oonf_log_get_libdata()->sharedlibrary_postfix)) {
-    end -= strlen(oonf_log_get_libdata()->sharedlibrary_prefix);
-  }
-  else if (str_endswith_nocase(&libname[start],
-      oonf_log_get_appdata()->sharedlibrary_postfix)) {
-    end -= strlen(oonf_log_get_appdata()->sharedlibrary_prefix);
-  }
-
-  if (end-start+1 <= sizeof(*pluginname)) {
-    memcpy(pluginname->name, &libname[start], end-start);
-  }
-}
-
-/**
- * Load a plugin and call its initialize callback
- * @param libname the name of the library(file)
- * @return plugin db object
- */
-struct oonf_subsystem *
-oonf_plugins_load(const char *libname)
-{
-  void *dlhandle;
-  struct oonf_subsystem *plugin;
-
-  /* see if the plugin is there */
-  if ((plugin = oonf_plugins_get(libname)) == NULL) {
-    /* attempt to load the plugin */
-    dlhandle = _open_plugin(libname);
-
-    if (dlhandle == NULL) {
-      /* Logging output has already been done by _open_plugin() */
-      return NULL;
-    }
-
-    /* plugin should be in the tree now */
-    if ((plugin = oonf_plugins_get(libname)) == NULL) {
-      OONF_WARN(LOG_PLUGINS, "dynamic library loading failed: \"%s\"!\n", dlerror());
-      dlclose(dlhandle);
-      return NULL;
-    }
-
-    plugin->_dlhandle = dlhandle;
-  }
-  return plugin;
-}
-
-/**
- * Call the initialization callback of a plugin to activate it
- * @param plugin pointer to plugin db object
- * @return -1 if initialization failed, 0 otherwise
- */
-int
-oonf_plugins_call_init(struct oonf_subsystem *plugin) {
-  if (!plugin->_initialized && plugin->init != NULL) {
-    if (plugin->init()) {
-      OONF_WARN(LOG_PLUGINS, "Init callback failed for plugin %s\n", plugin->name);
-      return -1;
-    }
-    OONF_INFO(LOG_PLUGINS, "Loaded plugin %s successful\n", plugin->name);
-
-    if (!plugin->no_logging) {
-      OONF_INFO(plugin->logging, "Plugin %s started", plugin->name);
-    }
-  }
-  plugin->_initialized = true;
-  return 0;
-}
-
-/**
- * Tell plugin it should begin to free its resources
- * @param plugin pointer to plugin db object
- */
-void
-oonf_plugins_initiate_unload(struct oonf_subsystem *plugin) {
-  if (plugin->initiate_shutdown) {
-    plugin->initiate_shutdown();
-    plugin->_unload_initiated = true;
-  }
-}
-
-/**
- * Unloads an active plugin. Static plugins cannot be removed until
- * final cleanup.
- * @param plugin pointer to plugin db object
- * @return 0 if plugin was removed, -1 otherwise
- */
-int
-oonf_plugins_unload(struct oonf_subsystem *plugin) {
-  if (plugin->initiate_shutdown != NULL && !plugin->_unload_initiated) {
-    return -1;
-  }
-  return _unload_plugin(plugin, false);
-}
-
-/**
- * Initialize plugin tree for early loading of static plugins
- */
-static void
-_init_plugin_tree(void) {
-  if (_plugin_tree_initialized) {
-    return;
-  }
-
-  avl_init(&oonf_plugin_tree, avl_comp_strcasecmp, false);
-  _plugin_tree_initialized = true;
-}
-
-/**
- * Internal helper function to unload a plugin using the old API
- * @param plugin pointer to plugin db object
- * @param cleanup true if this is the final cleanup
- *   before OONF shuts down, false otherwise
- * @return 0 if the plugin was removed, -1 otherwise
- */
-static int
-_unload_plugin(struct oonf_subsystem *plugin, bool cleanup) {
-  if (!plugin->can_cleanup && !cleanup) {
-    OONF_WARN(LOG_PLUGINS, "Plugin %s does not support unloading",
-        plugin->name);
-    return -1;
-  }
-
-  if (plugin->_initialized) {
-    OONF_INFO(LOG_PLUGINS, "Unloading plugin %s\n", plugin->name);
-
-    /* remove first from tree */
-    avl_delete(&oonf_plugin_tree, &plugin->_node);
-
-    /* cleanup */
-    if (plugin->cleanup) {
-      plugin->cleanup();
-    }
-    if (plugin->_dlhandle) {
-      dlclose(plugin->_dlhandle);
-    }
-  }
-  return 0;
-}
-
-/**
- * Internal helper to load plugin with different variants of the
- * filename.
- * @param filename pointer to filename
- */
-static void *
-_open_plugin(const char *filename) {
-  struct abuf_template_storage table;
-  struct autobuf abuf;
-  void *result;
-  size_t i;
-
-  if (abuf_init(&abuf)) {
-    OONF_WARN(LOG_PLUGINS, "Not enough memory for plugin name generation");
-    return NULL;
-  }
-
-  result = NULL;
-  _dlopen_data[IDX_DLOPEN_LIB].value = filename;
-
-  for (i=0; result == NULL && i<ARRAYSIZE(DLOPEN_PATTERNS); i++) {
-    abuf_template_init(&table,
-        _dlopen_data, ARRAYSIZE(_dlopen_data), DLOPEN_PATTERNS[i]);
-
-    abuf_clear(&abuf);
-    abuf_add_template(&abuf, &table, false);
-
-    result = dlopen(abuf_getptr(&abuf), RTLD_NOW);
-    if (!result) {
-      OONF_DEBUG(LOG_PLUGINS, "Loading of plugin file %s failed: %s",
-          abuf_getptr(&abuf), dlerror());
-    }
-  }
-  if (result == NULL) {
-    OONF_WARN(LOG_PLUGINS, "Loading of plugin %s failed.\n", filename);
-  }
-  else {
-    OONF_INFO(LOG_PLUGINS, "Loading plugin %s from %s\n", filename, abuf_getptr(&abuf));
-  }
-
-  abuf_free(&abuf);
-  return result;
-}
index e8dcd7f..0be983a 100644 (file)
  */
 
 #include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
 
+#include "common/autobuf.h"
 #include "common/common_types.h"
+#include "common/list.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/template.h"
 #include "config/cfg_schema.h"
-
-#include "core/oonf_subsystem.h"
+#include "core/oonf_libdata.h"
 #include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+
+/* constants */
+enum {
+  IDX_DLOPEN_LIB,
+  IDX_DLOPEN_PATH,
+  IDX_DLOPEN_PRE,
+  IDX_DLOPEN_PRELIB,
+  IDX_DLOPEN_POST,
+  IDX_DLOPEN_POSTLIB,
+  IDX_DLOPEN_VER,
+};
+
+static void _init_plugin_tree(void);
+static int _init_plugin(struct oonf_subsystem *plugin);
+static void _cleanup_plugin(struct oonf_subsystem *plugin);
+static int _unload_plugin(struct oonf_subsystem *plugin, bool cleanup);
+static void *_open_plugin(const char *filename, int *idx);
+static void *_open_plugin_template(const char *filename, int template, int mode);
+
+/*
+ * List of paths to look for plugins
+ *
+ * The elements of the patterns are:
+ *
+ * %LIB%:  name of the plugin
+ * %PATH%: local path (linux: ".")
+ *
+ * %PRE%:  shared library prefix defined by the app (linux: "lib<app>_")
+ * %POST%: shared library postfix defined by the app (linux: ".so")
+ * %VER:   version number as defined by the app (e.g. "0.1.0")
+ *
+ * %PRELIB%: shared library prefix defined by the API (linux: "liboonf_")
+ * %POST%:   shared library postfix defined by the app (linux: ".so")
+ * %VER:     version number as defined by the app (e.g. "0.1.0")
+ */
+static const char *DLOPEN_PATTERNS[] = {
+  "%PATH%/%PRE%%LIB%%POST%.%VER%",
+  "%PATH%/%PRELIB%%LIB%%POSTLIB%.%VER%",
+  "%PATH%/%PRE%%LIB%%POST%",
+  "%PATH%/%PRELIB%%LIB%%POSTLIB%",
+  "%PRE%%LIB%%POST%.%VER%",
+  "%PRELIB%%LIB%%POSTLIB%.%VER%",
+  "%PRE%%LIB%%POST%",
+  "%PRELIB%%LIB%%POSTLIB%",
+};
+
+/* Local functions */
+struct avl_tree oonf_plugin_tree;
+static bool _plugin_tree_initialized = false;
+
+/* library loading patterns */
+static struct abuf_template_data_entry _dlopen_data[] = {
+  [IDX_DLOPEN_LIB]     =  { .key = "LIB" },
+  [IDX_DLOPEN_PATH]    =  { .key = "PATH", .value = "." },
+  [IDX_DLOPEN_PRE]     =  { .key = "PRE" },
+  [IDX_DLOPEN_PRELIB]  =  { .key = "PRELIB" },
+  [IDX_DLOPEN_POST]    =  { .key = "POST" },
+  [IDX_DLOPEN_POSTLIB] =  { .key = "POSTLIB" },
+  [IDX_DLOPEN_VER]     =  { .key = "VER" },
+};
+
+struct autobuf _dlopen_data_buffer;
+
+/**
+ * Initialize the plugin loader system
+ */
+int
+oonf_plugins_init(void) {
+  if (abuf_init(&_dlopen_data_buffer)) {
+    return -1;
+  }
+
+  _init_plugin_tree();
+
+  /* load predefined values for dlopen templates */
+  _dlopen_data[IDX_DLOPEN_PRE].value =
+      oonf_log_get_appdata()->sharedlibrary_prefix;
+  _dlopen_data[IDX_DLOPEN_POST].value =
+      oonf_log_get_appdata()->sharedlibrary_postfix;
+
+  _dlopen_data[IDX_DLOPEN_PRELIB].value =
+      oonf_log_get_libdata()->sharedlibrary_prefix;
+  _dlopen_data[IDX_DLOPEN_POSTLIB].value =
+      oonf_log_get_libdata()->sharedlibrary_postfix;
+
+  _dlopen_data[IDX_DLOPEN_VER].value =
+      oonf_log_get_libdata()->lib_version;
+  return 0;
+}
+
+/**
+ * Disable and unload all plugins
+ */
+void
+oonf_plugins_cleanup(void) {
+  struct oonf_subsystem *plugin, *iterator;
+
+  avl_for_each_element_safe(&oonf_plugin_tree, plugin, _node, iterator) {
+    _unload_plugin(plugin, true);
+  }
+
+  abuf_free(&_dlopen_data_buffer);
+}
 
 void
 oonf_subsystem_configure(struct cfg_schema *schema,
@@ -98,3 +210,367 @@ oonf_subsystem_unconfigure(struct cfg_schema *schema,
     schema_section = schema_section->next_section;
   }
 }
+
+/**
+ * Sets the user-configured path to look for plugins
+ * @param path default path
+ */
+void
+oonf_plugins_set_path(const char *path) {
+  _dlopen_data[IDX_DLOPEN_PATH].value = path;
+}
+
+/**
+ * Tell plugins to begin to shutdown
+ */
+void
+oonf_plugins_initiate_shutdown(void) {
+  struct oonf_subsystem *plugin, *iterator;
+
+  avl_for_each_element_safe(&oonf_plugin_tree, plugin, _node, iterator) {
+    if (plugin->initiate_shutdown) {
+      plugin->initiate_shutdown();
+    }
+  }
+}
+
+/**
+ * This function is called by the constructor of a plugin to
+ * insert the plugin into the global list. It will be called before
+ * any subsystem was initialized!
+ * @param plugin pointer to plugin definition
+ */
+void
+oonf_plugins_hook(struct oonf_subsystem *plugin) {
+  /* make sure plugin tree is initialized */
+  _init_plugin_tree();
+
+  /* check if plugin is already in tree */
+  if (oonf_plugins_get(plugin->name)) {
+    return;
+  }
+
+  /* hook plugin into avl tree */
+  plugin->_node.key = plugin->name;
+  avl_insert(&oonf_plugin_tree, &plugin->_node);
+
+  fprintf(stderr, "plugin: %s\n", plugin->name);
+}
+
+/**
+ * Extracts the plugin name from a library name, including optional path,
+ * prefix and/or postfix
+ * @param libname library name
+ * @return pointer to buffer with plugin name, must be freed later
+ */
+void
+oonf_plugins_extract_name(
+    struct oonf_plugin_namebuf *pluginname, const char *libname) {
+  size_t start, end;
+  char *ptr;
+
+  memset(pluginname, 0, sizeof(*pluginname));
+
+  start = 0;
+  end = strlen(libname);
+
+  /* remove path */
+  if ((ptr = strrchr(libname, '/')) != NULL) {
+    start += (ptr - libname);
+  }
+  else if ((ptr = strrchr(libname, '\\')) != NULL) {
+    start += (ptr - libname);
+  }
+
+  /* remove (oonf/app) lib prefix */
+  if (str_startswith_nocase(&libname[start],
+      oonf_log_get_libdata()->sharedlibrary_prefix)) {
+    start += strlen(oonf_log_get_libdata()->sharedlibrary_prefix);
+  }
+  else if (str_startswith_nocase(&libname[start],
+      oonf_log_get_appdata()->sharedlibrary_prefix)) {
+    start += strlen(oonf_log_get_appdata()->sharedlibrary_prefix);
+  }
+
+  /* remove (oonf/app) lib postfix */
+  if (str_endswith_nocase(&libname[start],
+      oonf_log_get_libdata()->sharedlibrary_postfix)) {
+    end -= strlen(oonf_log_get_libdata()->sharedlibrary_prefix);
+  }
+  else if (str_endswith_nocase(&libname[start],
+      oonf_log_get_appdata()->sharedlibrary_postfix)) {
+    end -= strlen(oonf_log_get_appdata()->sharedlibrary_prefix);
+  }
+
+  if (end-start+1 <= sizeof(*pluginname)) {
+    memcpy(pluginname->name, &libname[start], end-start);
+  }
+}
+
+/**
+ * Load a plugin and call its initialize callback
+ * @param libname the name of the library(file)
+ * @return plugin db object
+ */
+struct oonf_subsystem *
+oonf_plugins_load(const char *libname)
+{
+  struct oonf_subsystem *plugin;
+  void *dlhandle;
+  int idx;
+
+  /* see if the plugin is there */
+  if ((plugin = oonf_plugins_get(libname)) == NULL) {
+    /* attempt to load the plugin */
+    dlhandle = _open_plugin(libname, &idx);
+
+    if (dlhandle == NULL) {
+      /* Logging output has already been done by _open_plugin() */
+      return NULL;
+    }
+
+    /* plugin should be in the tree now */
+    if ((plugin = oonf_plugins_get(libname)) == NULL) {
+      OONF_WARN(LOG_PLUGINS, "dynamic library loading failed: \"%s\"!\n", dlerror());
+      dlclose(dlhandle);
+      return NULL;
+    }
+
+    plugin->_dlhandle = dlhandle;
+    plugin->_dlpath_index = idx;
+  }
+  return plugin;
+}
+
+/**
+ * Call the initialization callback of a plugin to activate it.
+ * Make sure that dependencies are initialized before activating it.
+ * @param plugin pointer to plugin db object
+ * @return -1 if initialization failed, 0 otherwise
+ */
+int
+oonf_plugins_call_init(struct oonf_subsystem *plugin) {
+  /* start recursive dependency tracking */
+  return _init_plugin(plugin);
+}
+
+/**
+ * Tell plugin it should begin to free its resources
+ * @param plugin pointer to plugin db object
+ */
+void
+oonf_plugins_initiate_unload(struct oonf_subsystem *plugin) {
+  if (plugin->initiate_shutdown) {
+    plugin->initiate_shutdown();
+    plugin->_unload_initiated = true;
+  }
+}
+
+/**
+ * Unloads an active plugin. Static plugins cannot be removed until
+ * final cleanup.
+ * @param plugin pointer to plugin db object
+ * @return 0 if plugin was removed, -1 otherwise
+ */
+int
+oonf_plugins_unload(struct oonf_subsystem *plugin) {
+  if (plugin->initiate_shutdown != NULL && !plugin->_unload_initiated) {
+    return -1;
+  }
+  return _unload_plugin(plugin, false);
+}
+
+/**
+ * Initialize plugin tree for early loading of static plugins
+ */
+static void
+_init_plugin_tree(void) {
+  if (_plugin_tree_initialized) {
+    return;
+  }
+
+  avl_init(&oonf_plugin_tree, avl_comp_strcasecmp, false);
+  _plugin_tree_initialized = true;
+}
+
+/**
+ * Initialize plugin and all its dependencies
+ * @param plugin pointer to plugin
+ * @return -1 if plugin has missing dependency,
+ *    0 if dependencies were loaded,
+ *    1 if a circular dependency were detected
+ */
+static int
+_init_plugin(struct oonf_subsystem *plugin) {
+  struct oonf_subsystem *dep;
+  size_t i;
+  int result;
+
+  if (plugin->_initialized) {
+    return 0;
+  }
+
+  /* mark plugin */
+  plugin->_dependency_missing = true;
+
+  for (i=0; i<plugin->dependencies_count; i++) {
+    dep = oonf_plugins_get(plugin->dependencies[i]);
+    if (!dep) {
+      OONF_WARN(LOG_PLUGINS, "Dependency '%s' missing for '%s'",
+          plugin->dependencies[i], plugin->name);
+      return -1;
+    }
+
+    if (dep->_dependency_missing) {
+      OONF_WARN(LOG_PLUGINS, "Circular dependency, '%s' is dependency of '%s'",
+          plugin->dependencies[i], plugin->name);
+      return 1;
+    }
+
+    result = _init_plugin(dep);
+    if (result == -1) {
+      /* forward missing dependency */
+      return -1;
+    }
+    if (result == 1) {
+      /* forward circular dependency */
+      OONF_WARN(LOG_PLUGINS, "Circular dependency, '%s' is dependency of '%s'",
+          plugin->dependencies[i], plugin->name);
+      return 1;
+    }
+  }
+
+  plugin->_dependency_missing = false;
+
+  if (plugin->_dlhandle && !_open_plugin_template(plugin->name, plugin->_dlpath_index,
+      RTLD_LAZY | RTLD_NOLOAD | RTLD_GLOBAL)) {
+    OONF_WARN(LOG_PLUGINS, "Could not reload plugin '%s' into global namespace",
+        plugin->name);
+    return -1;
+  }
+
+  if (plugin->init) {
+    if (plugin->init()) {
+      OONF_WARN(LOG_PLUGINS, "Init callback failed for plugin %s\n", plugin->name);
+      return -1;
+    }
+  }
+
+  OONF_INFO(LOG_PLUGINS, "Initialized plugin %s successful\n", plugin->name);
+
+  if (!plugin->no_logging) {
+    OONF_INFO(plugin->logging, "Plugin %s started", plugin->name);
+  }
+
+  plugin->_initialized = true;
+  return 0;
+}
+
+static void
+_cleanup_plugin(struct oonf_subsystem *plugin) {
+  struct oonf_subsystem *rdep;
+  size_t i;
+
+  if (!plugin->_initialized) {
+    return;
+  }
+
+  /* handle reverse dependencies */
+  avl_for_each_element(&oonf_plugin_tree, rdep, _node) {
+    /* look for reverse dependency */
+    for (i=0; i<rdep->dependencies_count; i++) {
+      if (strcmp(rdep->dependencies[i], plugin->name) == 0) {
+        /* found a reverse dependency */
+        _cleanup_plugin(rdep);
+      }
+    }
+  }
+
+  if (plugin->cleanup) {
+    OONF_INFO(LOG_PLUGINS, "Cleanup plugin %s\n", plugin->name);
+    plugin->cleanup();
+  }
+  plugin->_initialized = false;
+}
+
+/**
+ * Internal helper function to unload a plugin using the old API
+ * @param plugin pointer to plugin db object
+ * @param cleanup true if this is the final cleanup
+ *   before OONF shuts down, false otherwise
+ * @return 0 if the plugin was removed, -1 otherwise
+ */
+static int
+_unload_plugin(struct oonf_subsystem *plugin, bool cleanup) {
+  if (!plugin->can_cleanup && !cleanup) {
+    OONF_WARN(LOG_PLUGINS, "Plugin %s does not support unloading",
+        plugin->name);
+    return -1;
+  }
+
+  if (plugin->_initialized) {
+    _cleanup_plugin(plugin);
+  }
+
+  OONF_INFO(LOG_PLUGINS, "Unloading plugin %s\n", plugin->name);
+
+  /* remove first from tree */
+  avl_delete(&oonf_plugin_tree, &plugin->_node);
+
+  /* cleanup */
+  if (plugin->_dlhandle) {
+    dlclose(plugin->_dlhandle);
+  }
+  return 0;
+}
+
+static void *
+_open_plugin_template(const char *filename, int template, int mode) {
+  struct abuf_template_storage table;
+  void *result;
+
+  _dlopen_data[IDX_DLOPEN_LIB].value = filename;
+
+  abuf_template_init(&table,
+      _dlopen_data, ARRAYSIZE(_dlopen_data), DLOPEN_PATTERNS[template]);
+
+  abuf_clear(&_dlopen_data_buffer);
+  abuf_add_template(&_dlopen_data_buffer, &table, false);
+
+  OONF_DEBUG(LOG_PLUGINS, "dlopen (%s,0x%x)...",
+        abuf_getptr(&_dlopen_data_buffer), mode);
+
+  result = dlopen(abuf_getptr(&_dlopen_data_buffer), mode);
+  if (!result) {
+    OONF_DEBUG(LOG_PLUGINS, "dlopen (%s,0x%x) failed: %s",
+        abuf_getptr(&_dlopen_data_buffer), mode, dlerror());
+  }
+  else {
+    OONF_INFO(LOG_PLUGINS, "dlopen (%s,0x%x) succeeded\n",
+        abuf_getptr(&_dlopen_data_buffer), mode);
+  }
+  return result;
+}
+
+/**
+ * Internal helper to load plugin with different variants of the
+ * filename.
+ * @param filename pointer to filename
+ */
+static void *
+_open_plugin(const char *filename, int *idx) {
+  void *result;
+  size_t i;
+
+  result = NULL;
+  for (i=0; i<ARRAYSIZE(DLOPEN_PATTERNS); i++) {
+    result = _open_plugin_template(filename, i, RTLD_LAZY | RTLD_LOCAL);
+    if (result) {
+      *idx = i;
+      return result;
+    }
+  }
+
+  OONF_WARN(LOG_PLUGINS, "Loading of plugin %s failed.\n", filename);
+  return NULL;
+}
index 87a1842..60213f6 100644 (file)
@@ -53,6 +53,8 @@
 
 #define OONF_SUBSYSTEM_NAMESIZE 32
 
+#define DECLARE_OONF_PLUGIN(subsystem) EXPORT void hookup_plugin_ ## subsystem (void) __attribute__ ((constructor)); void hookup_plugin_ ## subsystem (void) { oonf_plugins_hook(&subsystem); }
+
 /*
  * description of a subsystem of the OONF-API.
  * In theory, ALL fields except for name are optional.
@@ -61,6 +63,10 @@ struct oonf_subsystem {
   /* name of the subsystem */
   const char *name;
 
+  /* list of dependencies of this subsystem */
+  const char **dependencies;
+  size_t dependencies_count;
+
   /* description of the subsystem */
   const char *descr;
 
@@ -115,12 +121,21 @@ struct oonf_subsystem {
   enum oonf_log_source logging;
 
   /* true if the subsystem is initialized */
-  bool _initialized, _unload_initiated;
+  bool _initialized;
+
+  /* true if unload of plugin is in progress */
+  bool _unload_initiated;
+
+  /* temporary variable to detect circular dependencies */
+  bool _dependency_missing;
 
   /* pointer to dlopen handle */
   void *_dlhandle;
 
-  /* tree for dynamic subsystems */
+  /* which template was used to load plugin */
+  int _dlpath_index;
+
+  /* hook into subsystem tree */
   struct avl_node _node;
 };
 
@@ -129,6 +144,41 @@ EXPORT void oonf_subsystem_configure(struct cfg_schema *schema,
 EXPORT void oonf_subsystem_unconfigure(struct cfg_schema *schema,
     struct oonf_subsystem *subsystem);
 
+struct oonf_plugin_namebuf {
+  char name[OONF_SUBSYSTEM_NAMESIZE];
+};
+
+EXPORT extern struct avl_tree oonf_plugin_tree;
+
+EXPORT int oonf_plugins_init(void);
+EXPORT void oonf_plugins_initiate_shutdown(void);
+EXPORT void oonf_plugins_cleanup(void);
+EXPORT void oonf_plugins_set_path(const char *path);
+
+EXPORT void oonf_plugins_hook(struct oonf_subsystem *subsystem);
+
+EXPORT int oonf_plugins_call_init(struct oonf_subsystem *plugin);
+EXPORT void oonf_plugins_call_cleanup(struct oonf_subsystem *plugin);
+
+EXPORT void oonf_plugins_extract_name(
+    struct oonf_plugin_namebuf *buf, const char *libname);
+
+EXPORT struct oonf_subsystem *oonf_plugins_load(const char *);
+EXPORT void oonf_plugins_initiate_unload(struct oonf_subsystem *);
+EXPORT int oonf_plugins_unload(struct oonf_subsystem *);
+
+/**
+ * Query for a certain plugin name
+ * @param libname name of plugin
+ * @return pointer to plugin db entry, NULL if not found
+ */
+static INLINE struct oonf_subsystem *
+oonf_plugins_get(const char *libname) {
+  struct oonf_subsystem *plugin;
+
+  return avl_find_element(&oonf_plugin_tree, libname, plugin, _node);
+}
+
 static INLINE bool
 oonf_subsystem_is_initialized(struct oonf_subsystem *subsystem) {
   return subsystem->_initialized;
index 9625e6a..7d3edf3 100644 (file)
@@ -46,6 +46,7 @@
 #include "common/avl_comp.h"
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
+
 #include "subsystems/oonf_class.h"
 
 /* prototypes */
@@ -69,10 +70,11 @@ const char *OONF_CLASS_EVENT_NAME[] = {
 
 /* subsystem definition */
 struct oonf_subsystem oonf_class_subsystem = {
-  .name = "class",
+  .name = OONF_CLASS_SUBSYSTEM,
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_class_subsystem);
 
 /**
  * Initialize the class system
index b738761..cdef5db 100644 (file)
@@ -46,6 +46,8 @@
 #include "common/list.h"
 #include "common/avl.h"
 
+#define OONF_CLASS_SUBSYSTEM "class"
+
 enum oonf_class_event {
   OONF_OBJECT_CHANGED,
   OONF_OBJECT_ADDED,
index dbf8165..66b09bc 100644 (file)
@@ -54,6 +54,7 @@
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/os_clock.h"
+
 #include "subsystems/oonf_clock.h"
 
 /* prototypes */
@@ -65,10 +66,18 @@ static uint64_t now_times;
 /* arbitrary timestamp that represents the time oonf_clock_init() was called */
 static uint64_t start_time;
 
+/* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_OS_CLOCK_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_clock_subsystem = {
-  .name = "clock",
+  .name = OONF_CLOCK_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
 };
+DECLARE_OONF_PLUGIN(oonf_clock_subsystem);
 
 /**
  * Initialize olsr clock system
index 737c774..bfb0412 100644 (file)
@@ -47,6 +47,8 @@
 #include "config/cfg.h"
 #include "config/cfg_schema.h"
 
+#define OONF_CLOCK_SUBSYSTEM "clock"
+
 /* Some defs for juggling with timers */
 #define MSEC_PER_SEC 1000
 #define USEC_PER_SEC 1000000
index 636bfc7..cb3d5df 100644 (file)
@@ -47,6 +47,7 @@
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_timer.h"
+
 #include "subsystems/oonf_duplicate_set.h"
 
 /* prototypes */
@@ -80,11 +81,19 @@ const char *OONF_DUPSET_RESULT_STR[OONF_DUPSET_MAX] = {
 };
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_duplicate_set_subsystem = {
-  .name = "duplicate_set",
+  .name = OONF_DUPSET_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_duplicate_set_subsystem);
 
 /**
  * Initialize duplicate set subsystem
index d1d6fe8..0917583 100644 (file)
@@ -47,6 +47,8 @@
 #include "common/netaddr.h"
 #include "subsystems/oonf_timer.h"
 
+#define OONF_DUPSET_SUBSYSTEM "dupset"
+
 enum { OONF_DUPSET_MAXIMUM_TOO_OLD = 8 };
 
 enum oonf_duplicate_result {
index 8e41442..fc5f268 100644 (file)
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
 #include "core/os_core.h"
-#include "subsystems/oonf_http.h"
 #include "subsystems/oonf_stream_socket.h"
 
+#include "subsystems/oonf_http.h"
+
 /* Http text constants */
 static const char HTTP_VERSION_1_0[] = "HTTP/1.0";
 static const char HTTP_VERSION_1_1[] = "HTTP/1.1";
@@ -111,7 +112,7 @@ static struct cfg_schema_entry _http_entries[] = {
 };
 
 static struct cfg_schema_section _http_section = {
-  .type = "http",
+  .type = OONF_HTTP_SUBSYSTEM,
   .mode = CFG_SSMODE_UNNAMED_OPTIONAL_STARTUP_TRIGGER,
   .entries = _http_entries,
   .entry_count = ARRAYSIZE(_http_entries),
@@ -134,12 +135,19 @@ static struct oonf_stream_managed _http_managed_socket = {
 };
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_STREAM_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_http_subsystem = {
-  .name = "http",
+  .name = OONF_HTTP_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
   .cfg_section = &_http_section,
 };
+DECLARE_OONF_PLUGIN(oonf_http_subsystem);
 
 /**
  * Initialize http subsystem
@@ -423,7 +431,7 @@ _create_http_error(struct oonf_stream_session *session,
     enum oonf_http_result error) {
   abuf_appendf(&session->out, "<html><head><title>%s %s http server</title></head>"
       "<body><h1>HTTP error %d: %s</h1></body></html>",
-      oonf_log_get_appdata()->app_name, oonf_log_get_appdata()->app_version,
+      oonf_log_get_appdata()->app_name, oonf_log_get_libdata()->lib_version,
       error, _get_headertype_string(error));
   _create_http_header(session, error, NULL);
 }
@@ -522,7 +530,7 @@ _create_http_header(struct oonf_stream_session *session,
 
   /* Server version */
   abuf_appendf(&buf, "Server: %s\r\n",
-      oonf_log_get_appdata()->app_version);
+      oonf_log_get_libdata()->lib_version);
 
   /* connection-type */
   abuf_puts(&buf, "Connection: closed\r\n");
index 814b7af..dc286f9 100644 (file)
@@ -49,6 +49,8 @@
 #include "common/string.h"
 #include "subsystems/oonf_stream_socket.h"
 
+#define OONF_HTTP_SUBSYSTEM "http"
+
 /* built in parameters for header parser */
 enum {
   OONF_HTTP_MAX_HEADERS = 16,
index 7df1012..70d90c2 100644 (file)
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
-#include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_timer.h"
 #include "subsystems/os_net.h"
 #include "subsystems/os_system.h"
 
+#include "subsystems/oonf_interface.h"
+
 /* timeinterval to delay change in interface to trigger actions */
 #define OONF_INTERFACE_CHANGE_INTERVAL 100
 
@@ -80,11 +81,21 @@ static void _trigger_change_timer(struct oonf_interface *);
 struct avl_tree oonf_interface_tree;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_OS_NET_SUBSYSTEM,
+  OONF_OS_SYSTEM_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_interface_subsystem = {
-  .name = "interface",
+  .name = OONF_INTERFACE_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_interface_subsystem);
 
 static struct list_entity _interface_listener;
 static struct oonf_timer_class _change_timer_info = {
index 8cf2e6d..d47faf1 100644 (file)
@@ -51,6 +51,8 @@
 #include "subsystems/oonf_timer.h"
 #include "subsystems/os_net.h"
 
+#define OONF_INTERFACE_SUBSYSTEM "interface"
+
 /* memory class for oonf interfaces */
 #define OONF_CLASS_INTERFACE             "oonf_interface"
 
index f42939a..f5694b3 100644 (file)
@@ -46,6 +46,8 @@
 #include "config/cfg_schema.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
+#include "subsystems/oonf_interface.h"
+
 #include "subsystems/oonf_layer2.h"
 
 /* prototypes */
@@ -56,11 +58,19 @@ static void _net_remove(struct oonf_layer2_net *l2net);
 static void _neigh_remove(struct oonf_layer2_neigh *l2neigh);
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_layer2_subsystem = {
-    .name = "layer2",
-    .init = _init,
-    .cleanup = _cleanup,
+  .name = OONF_LAYER2_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .init = _init,
+  .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_layer2_subsystem);
 
 /* layer2 neighbor metadata */
 const struct oonf_layer2_metadata oonf_layer2_metadata_neigh[OONF_LAYER2_NEIGH_COUNT] = {
index 3c14d18..0f9c69e 100644 (file)
@@ -46,7 +46,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_interface.h"
-#include "subsystems/oonf_timer.h"
+
+#define OONF_LAYER2_SUBSYSTEM "layer2"
 
 #define LAYER2_CLASS_NEIGHBOR    "layer2_neighbor"
 #define LAYER2_CLASS_NETWORK     "layer2_network"
index 4fe69e2..312d17c 100644 (file)
 #include "common/netaddr_acl.h"
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
-#include "rfc5444/rfc5444_iana.h"
-#include "subsystems/os_net.h"
-#include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_socket.h"
+#include "subsystems/os_net.h"
+
+#include "subsystems/oonf_packet_socket.h"
 
 /* prototypes */
 static int _init(void);
@@ -75,11 +75,20 @@ static void _cb_packet_event(int fd, void *data, bool r, bool w, bool mc);
 static void _cb_interface_listener(struct oonf_interface_listener *l);
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_SOCKET_SUBSYSTEM,
+  OONF_OS_NET_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_packet_socket_subsystem = {
   .name = "packet",
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_packet_socket_subsystem);
 
 /* other global variables */
 static struct list_entity _packet_sockets = { NULL, NULL };
index 2cf40e4..4e77df9 100644 (file)
@@ -56,6 +56,8 @@
 #define IF_NAMESIZE 16
 #endif
 
+#define OONF_PACKET_SUBSYSTEM "packet"
+
 struct oonf_packet_socket;
 
 struct oonf_packet_config {
index ede301e..2658db4 100644 (file)
 #include "core/oonf_subsystem.h"
 #include "core/os_core.h"
 #include "subsystems/oonf_class.h"
+#include "subsystems/oonf_duplicate_set.h"
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_timer.h"
-#include "subsystems/oonf_duplicate_set.h"
+
 #include "subsystems/oonf_rfc5444.h"
 
 /* constants and definitions */
@@ -239,12 +240,22 @@ static struct oonf_rfc5444_protocol *_rfc5444_protocol = NULL;
 static struct oonf_rfc5444_interface *_rfc5444_unicast = NULL;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_DUPSET_SUBSYSTEM,
+  OONF_PACKET_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_rfc5444_subsystem = {
   .name = "rfc5444",
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
   .cfg_section = &_interface_section,
 };
+DECLARE_OONF_PLUGIN(oonf_rfc5444_subsystem);
 
 /**
  * Initialize RFC5444 handling system
index bd1081a..ab70aaa 100644 (file)
 #include "rfc5444/rfc5444_reader.h"
 #include "rfc5444/rfc5444_writer.h"
 #include "subsystems/oonf_duplicate_set.h"
-#include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_timer.h"
 
-/* suggested priorities for RFC5444 readers */
+#define OONF_RFC5444_SUBSYSTEM "rfc5444"
 
+/* suggested priorities for RFC5444 readers */
 enum {
   RFC5444_VALIDATOR_PRIORITY = -256,
   RFC5444_MAIN_PARSER_PRIORITY = 0,
index 8837bb7..635a36a 100644 (file)
 #include "common/avl_comp.h"
 #include "subsystems/oonf_clock.h"
 #include "core/oonf_logging.h"
+#include "core/oonf_main.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/os_net.h"
-#include "subsystems/oonf_socket.h"
 #include "subsystems/oonf_timer.h"
 
+#include "subsystems/oonf_socket.h"
+
 /* prototypes */
 static int _init(void);
 static void _cleanup(void);
+static void _initiate_shutdown(void);
+static int _handle_scheduling(void);
+
+/* time until the scheduler should run */
+uint64_t _scheduler_time_limit;
 
 /* List of all active sockets in scheduler */
 struct list_entity oonf_socket_head;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_TIMER_SUBSYSTEM,
+  OONF_OS_NET_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_socket_subsystem = {
-  .name = "socket",
+  .name = OONF_SOCKET_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
+  .initiate_shutdown = _initiate_shutdown,
 };
+DECLARE_OONF_PLUGIN(oonf_socket_subsystem);
 
 /**
  * Initialize olsr socket scheduler
@@ -74,6 +90,10 @@ struct oonf_subsystem oonf_socket_subsystem = {
  */
 static int
 _init(void) {
+  if (oonf_main_set_scheduler(_handle_scheduling)) {
+    return -1;
+  }
+
   list_init_head(&oonf_socket_head);
   return 0;
 }
@@ -93,6 +113,12 @@ _cleanup(void)
   }
 }
 
+static void
+_initiate_shutdown(void) {
+  /* stop within 500 ms */
+  _scheduler_time_limit = oonf_clock_get_absolute(500);
+}
+
 /**
  * Add a socket handler to the scheduler
  *
@@ -123,27 +149,19 @@ oonf_socket_remove(struct oonf_socket_entry *entry)
 }
 
 /**
- * Handle all incoming socket events until a certain time
- * @param stop_scheduler pointer to a callback function that tells
- *   the scheduler if it should return to the mainloop. Might be NULL.
- * @param stop_time timestamp when the handler should stop,
- *   0 if it should keep running
+ * Handle all incoming socket events and timer events
  * @return -1 if an error happened, 0 otherwise
  */
 int
-oonf_socket_handle(bool (*stop_scheduler)(void), uint64_t stop_time)
+_handle_scheduling(void)
 {
   struct oonf_socket_entry *entry, *iterator;
-  uint64_t next_event;
+  uint64_t next_event, stop_time;
   struct timeval tv, *tv_ptr;
   int n = 0;
   bool fd_read;
   bool fd_write;
 
-  if (stop_time == 0) {
-    stop_time = ~0ull;
-  }
-
   while (true) {
     fd_set ibits, obits;
     int hfd = 0;
@@ -153,13 +171,20 @@ oonf_socket_handle(bool (*stop_scheduler)(void), uint64_t stop_time)
       return -1;
     }
 
+    if (_scheduler_time_limit > 0) {
+      stop_time = _scheduler_time_limit;
+    }
+    else {
+      stop_time = ~0ull;
+    }
+
     if (oonf_clock_getNow() >= stop_time) {
       return 0;
     }
 
     oonf_timer_walk();
 
-    if (stop_scheduler != NULL && stop_scheduler()) {
+    if (!_scheduler_time_limit && oonf_main_shall_stop_scheduler()) {
       return 0;
     }
 
@@ -208,7 +233,7 @@ oonf_socket_handle(bool (*stop_scheduler)(void), uint64_t stop_time)
     }
 
     do {
-      if (stop_scheduler != NULL && stop_scheduler()) {
+      if (!_scheduler_time_limit && oonf_main_shall_stop_scheduler()) {
         return 0;
       }
       n = os_net_select(hfd,
index 5d77047..7d55135 100644 (file)
@@ -48,9 +48,7 @@
 #include "common/netaddr_acl.h"
 #include "subsystems/os_net.h"
 
-/* prototype for socket handler */
-typedef void (*socket_handler_func) (int fd, void *data,
-    bool event_read, bool event_write);
+#define OONF_SOCKET_SUBSYSTEM "socket"
 
 /* This struct represents a single registered socket handler */
 struct oonf_socket_entry {
@@ -58,7 +56,8 @@ struct oonf_socket_entry {
   int fd;
 
   /* socket handler */
-  socket_handler_func process;
+  void (*process) (int fd, void *data,
+      bool event_read, bool event_write);
 
   /* custom data pointer for sockets */
   void *data;
@@ -74,8 +73,6 @@ struct oonf_socket_entry {
 EXPORT extern struct oonf_subsystem oonf_socket_subsystem;
 EXPORT extern struct list_entity oonf_socket_head;
 
-EXPORT int oonf_socket_handle(bool (*stop_scheduler)(void), uint64_t) __attribute__((warn_unused_result));
-
 EXPORT void oonf_socket_add(struct oonf_socket_entry *);
 EXPORT void oonf_socket_remove(struct oonf_socket_entry *);
 
index 3932987..77ed4dc 100644 (file)
@@ -53,6 +53,7 @@
 #include "subsystems/oonf_socket.h"
 #include "subsystems/oonf_timer.h"
 #include "subsystems/os_net.h"
+
 #include "subsystems/oonf_stream_socket.h"
 
 /* prototypes */
@@ -88,11 +89,22 @@ static struct oonf_timer_class _connection_timeout = {
 };
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_SOCKET_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_OS_NET_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_stream_socket_subsystem = {
-  .name = "stream",
+  .name = OONF_STREAM_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_stream_socket_subsystem);
 
 /**
  * Initialize the stream socket handlers
index 06af07d..d2918d5 100644 (file)
@@ -53,6 +53,8 @@
 #include "subsystems/oonf_socket.h"
 #include "subsystems/oonf_timer.h"
 
+#define OONF_STREAM_SUBSYSTEM "stream"
+
 enum oonf_stream_session_state {
   STREAM_SESSION_ACTIVE,
   STREAM_SESSION_SEND_AND_QUIT,
index db79726..4305fd4 100644 (file)
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_stream_socket.h"
-#include "subsystems/oonf_telnet.h"
 #include "subsystems/oonf_timer.h"
 
+#include "subsystems/oonf_telnet.h"
+
 /* static function prototypes */
 static int _init(void);
 static void _cleanup(void);
@@ -92,7 +93,7 @@ static struct cfg_schema_entry _telnet_entries[] = {
 };
 
 static struct cfg_schema_section _telnet_section = {
-  .type = "telnet",
+  .type = OONF_TELNET_SUBSYSTEM,
   .mode = CFG_SSMODE_UNNAMED,
   .help = "Settings for the telnet interface",
   .cb_delta_handler = _cb_config_changed,
@@ -116,12 +117,21 @@ static struct oonf_telnet_command _builtin[] = {
 };
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_STREAM_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_telnet_subsystem = {
-  .name = "telnet",
+  .name = OONF_TELNET_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
   .cfg_section = &_telnet_section,
 };
+DECLARE_OONF_PLUGIN(oonf_telnet_subsystem);
 
 /* telnet session handling */
 static struct oonf_class _telnet_memcookie = {
index 490a389..1f8044a 100644 (file)
@@ -49,6 +49,8 @@
 #include "common/netaddr_acl.h"
 #include "subsystems/oonf_stream_socket.h"
 
+#define OONF_TELNET_SUBSYSTEM "telnet"
+
 enum oonf_telnet_result {
   TELNET_RESULT_ACTIVE,
   TELNET_RESULT_CONTINOUS,
index 931ca7c..b0823aa 100644 (file)
@@ -50,6 +50,7 @@
 #include "core/oonf_subsystem.h"
 #include "core/os_core.h"
 #include "subsystems/oonf_clock.h"
+
 #include "subsystems/oonf_timer.h"
 
 /* prototypes */
@@ -72,11 +73,18 @@ static bool _scheduling_now;
 struct list_entity oonf_timer_info_list;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_CLOCK_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_timer_subsystem = {
-  .name = "timer",
+  .name = OONF_TIMER_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_timer_subsystem);
 
 /**
  * Initialize timer scheduler subsystem
index b701b71..1009dd5 100644 (file)
@@ -48,6 +48,8 @@
 
 #include "subsystems/oonf_clock.h"
 
+#define OONF_TIMER_SUBSYSTEM "timer"
+
 struct oonf_timer_instance;
 
 /*
index da7b211..84cb466 100644 (file)
@@ -66,10 +66,11 @@ static const char _telnet_help[] =
 
 /* subsystem definition */
 struct oonf_subsystem oonf_viewer_subsystem = {
-  .name = "viewer",
+  .name = OONF_VIEWER_SUBSYSTEM,
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_viewer_subsystem);
 
 /**
  * Initialize telnet subsystem
index e4b0f8f..c4c031b 100644 (file)
@@ -47,6 +47,8 @@
 
 #include "core/oonf_subsystem.h"
 
+#define OONF_VIEWER_SUBSYSTEM "viewer"
+
 #define OONF_VIEWER_RAW_FORMAT      "raw"
 #define OONF_VIEWER_HEAD_FORMAT     "head"
 #define OONF_VIEWER_JSON_FORMAT     "json"
index 3d5b331..ed4f0cd 100644 (file)
@@ -48,6 +48,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_OS_CLOCK_SUBSYSTEM "os_clock"
+
 #define MSEC_PER_SEC 1000
 #define USEC_PER_MSEC 1000
 
index e51a14b..167e542 100644 (file)
@@ -55,10 +55,11 @@ static int _clock_source = 0;
 
 /* subsystem definition */
 struct oonf_subsystem oonf_os_clock_subsystem = {
-  .name = "os_clock",
+  .name = OONF_OS_CLOCK_SUBSYSTEM,
   .init = _init,
   .no_logging = true,
 };
+DECLARE_OONF_PLUGIN(oonf_os_clock_subsystem);
 
 /**
  * Initialize os-specific subsystem
index efe1429..79d66f1 100644 (file)
 #include <unistd.h>
 
 #include "common/common_types.h"
-
 #include "core/oonf_logging.h"
 #include "core/oonf_subsystem.h"
+#include "subsystems/oonf_timer.h"
+
 #include "subsystems/os_net.h"
 
 /* ip forwarding */
@@ -81,11 +82,18 @@ static unsigned _os_linux_get_base_ifindex(const char *interf);
 static int _ioctl_v4, _ioctl_v6;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_TIMER_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_os_net_subsystem = {
-  .name = "os_net",
+  .name = OONF_OS_NET_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_os_net_subsystem);
 
 /* global procfile state before initialization */
 static char _original_rp_filter;
index fad89de..c12a47a 100644 (file)
 
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
-#include "subsystems/os_routing.h"
 #include "subsystems/os_system.h"
 
+#include "subsystems/os_routing.h"
+
 /* prototypes */
 static int _init(void);
 static void _cleanup(void);
@@ -75,11 +76,18 @@ struct os_system_netlink _rtnetlink_socket = {
 struct list_entity _rtnetlink_feedback;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_OS_SYSTEM_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_os_routing_subsystem = {
-  .name = "os_routing",
+  .name = OONF_OS_ROUTING_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_os_routing_subsystem);
 
 /* default wildcard route */
 const struct os_route OS_ROUTE_WILDCARD = {
index 02b7a07..74b56e3 100644 (file)
@@ -59,6 +59,7 @@
 #include "common/string.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_socket.h"
+
 #include "subsystems/os_system.h"
 
 #ifndef SOL_NETLINK
@@ -144,11 +145,18 @@ const uint32_t _rtnetlink_mcast[] = {
 struct list_entity _ifchange_listener;
 
 /* subsystem definition */
+static const char *_dependencies[] = {
+  OONF_SOCKET_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_os_system_subsystem = {
-  .name = "os_system",
+  .name = OONF_OS_SYSTEM_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 };
+DECLARE_OONF_PLUGIN(oonf_os_system_subsystem);
 
 /* tracking of used netlink sequence numbers */
 static uint32_t _seq_used = 0;
index 15c063d..74b9c7a 100644 (file)
@@ -52,6 +52,8 @@
 #include "core/oonf_logging.h"
 #include "subsystems/oonf_timer.h"
 
+#define OONF_OS_NET_SUBSYSTEM "os_net"
+
 struct oonf_interface_data {
   /* Interface addresses with mesh-wide scope (at least) */
   const struct netaddr *if_v4, *if_v6;
index 5013768..8bf2ef6 100644 (file)
@@ -52,6 +52,8 @@
 #include "core/oonf_logging.h"
 #include "subsystems/os_system.h"
 
+#define OONF_OS_ROUTING_SUBSYSTEM "os_routing"
+
 /* include os-specific headers */
 #if defined(__linux__)
 #include "subsystems/os_linux/os_routing_linux.h"
index d9ff56a..bd717ea 100644 (file)
@@ -49,6 +49,8 @@
 #include "common/list.h"
 #include "core/oonf_logging.h"
 
+#define OONF_OS_SYSTEM_SUBSYSTEM "os_system"
+
 #define MSEC_PER_SEC 1000
 #define USEC_PER_MSEC 1000
 
index f7d4f02..fa418a4 100644 (file)
@@ -1,20 +1,9 @@
-# add subdirectories
-add_subdirectory(cfg_compact)
-add_subdirectory(httptelnet)
-add_subdirectory(layer2info)
-add_subdirectory(layer2_generator)
-add_subdirectory(link_config)
-add_subdirectory(plugin_controller)
-add_subdirectory(remotecontrol)
-add_subdirectory(dlep)
-
-# UCI specific library necessary for Openwrt config loader
-IF (UCI)
-    add_subdirectory(cfg_uciloader)
-ENDIF (UCI)
+# add include directoy
+include_directories(generic)
+include_directories(nhdp)
+include_directories(olsrv2)
 
-# linux specific plugins
-IF (LINUX)
-    add_subdirectory(nl80211_listener)
-    add_subdirectory(eth_listener)
-ENDIF (LINUX)
+# add subdirectories
+add_subdirectory(generic)
+add_subdirectory(nhdp)
+add_subdirectory(olsrv2)
diff --git a/src-plugins/generic/CMakeLists.txt b/src-plugins/generic/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f7d4f02
--- /dev/null
@@ -0,0 +1,20 @@
+# add subdirectories
+add_subdirectory(cfg_compact)
+add_subdirectory(httptelnet)
+add_subdirectory(layer2info)
+add_subdirectory(layer2_generator)
+add_subdirectory(link_config)
+add_subdirectory(plugin_controller)
+add_subdirectory(remotecontrol)
+add_subdirectory(dlep)
+
+# UCI specific library necessary for Openwrt config loader
+IF (UCI)
+    add_subdirectory(cfg_uciloader)
+ENDIF (UCI)
+
+# linux specific plugins
+IF (LINUX)
+    add_subdirectory(nl80211_listener)
+    add_subdirectory(eth_listener)
+ENDIF (LINUX)
similarity index 99%
rename from src-plugins/cfg_compact/cfg_compact.c
rename to src-plugins/generic/cfg_compact/cfg_compact.c
index 0298207..99714e8 100644 (file)
@@ -49,7 +49,7 @@
 #include "common/autobuf.h"
 #include "config/cfg_io.h"
 #include "config/cfg.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 
 #include "core/oonf_cfg.h"
 
@@ -68,7 +68,7 @@ static int _parse_line(struct cfg_db *db, char *line, char *section, size_t sect
     char *name, size_t name_size, struct autobuf *log);
 
 struct oonf_subsystem oonf_cfg_compact_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_CFG_COMPACT_SUBSYSTEM,
   .descr = "OONFD compact configuration file handler",
   .author = "Henning Rogge",
 
similarity index 97%
rename from src-plugins/cfg_compact/cfg_compact.h
rename to src-plugins/generic/cfg_compact/cfg_compact.h
index a92513d..5288b65 100644 (file)
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_CFG_COMPACT_SUBSYSTEM "cfg_compact"
+
 EXPORT extern struct oonf_subsystem oonf_cfg_compact_subsystem;
 
 #endif /* CFG_COMPACT_H_ */
@@ -65,7 +65,7 @@ static int _load_section(struct uci_section *sec, struct cfg_db *db, const char
 
 
 struct oonf_subsystem oonf_cfg_uciloader_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_CFG_UCILOADER_SUBSYSTEM,
   .descr = "OONF uci handler for configuration system",
   .author = "Henning Rogge",
 
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_CFG_UCILOADER_SUBSYSTEM "cfg_uciloader"
+
 #define UCI_OPTION_FOR_SECTION_NAME "name"
 
 EXPORT extern struct oonf_subsystem oonf_cfg_uciloader_subsystem;
similarity index 92%
rename from src-plugins/dlep/radio/dlep_radio.c
rename to src-plugins/generic/dlep/radio/dlep_radio.c
index a7cc066..0e4d063 100644 (file)
@@ -48,8 +48,9 @@
 #include "common/netaddr.h"
 
 #include "config/cfg_schema.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
+#include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_stream_socket.h"
 #include "subsystems/oonf_timer.h"
@@ -98,16 +99,25 @@ static struct cfg_schema_entry _radio_entries[] = {
 };
 
 static struct cfg_schema_section _radio_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_DLEP_RADIO_SUBSYSTEM,
   .mode = CFG_SSMODE_NAMED,
   .cb_delta_handler = _cb_config_changed,
   .entries = _radio_entries,
   .entry_count = ARRAYSIZE(_radio_entries),
 };
 
-/* plugin declaration */
+/* subsystem declaration */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_PACKET_SUBSYSTEM,
+  OONF_STREAM_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
 struct oonf_subsystem dlep_radio_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_DLEP_RADIO_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONF DLEP radio plugin",
   .author = "Henning Rogge",
 
@@ -175,8 +185,8 @@ _cb_config_changed(void) {
   /* read configuration */
   if (cfg_schema_tobin(interface, _radio_section.post,
       _radio_entries, ARRAYSIZE(_radio_entries))) {
-    OONF_WARN(LOG_DLEP_RADIO, "Could not convert %s config to bin",
-        OONF_PLUGIN_GET_NAME());
+    OONF_WARN(LOG_DLEP_RADIO, "Could not convert "
+        OONF_DLEP_RADIO_SUBSYSTEM " config to bin");
     return;
   }
 
similarity index 97%
rename from src-plugins/dlep/radio/dlep_radio.h
rename to src-plugins/generic/dlep/radio/dlep_radio.h
index 7175437..b74dfa5 100644 (file)
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_DLEP_RADIO_SUBSYSTEM "dlep_radio"
+
 #define LOG_DLEP_RADIO dlep_radio_subsystem.logging
 EXPORT extern struct oonf_subsystem dlep_radio_subsystem;
 
similarity index 92%
rename from src-plugins/dlep/router/dlep_router.c
rename to src-plugins/generic/dlep/router/dlep_router.c
index 3ec2425..d482e57 100644 (file)
@@ -48,7 +48,7 @@
 #include "common/netaddr.h"
 
 #include "config/cfg_schema.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_packet_socket.h"
@@ -92,7 +92,7 @@ static struct cfg_schema_entry _router_entries[] = {
 };
 
 static struct cfg_schema_section _router_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_DLEP_ROUTER_SUBSYSTEM,
   .mode = CFG_SSMODE_NAMED,
   .cb_delta_handler = _cb_config_changed,
   .entries = _router_entries,
@@ -100,8 +100,17 @@ static struct cfg_schema_section _router_section = {
 };
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_PACKET_SUBSYSTEM,
+  OONF_STREAM_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
 struct oonf_subsystem dlep_router_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_DLEP_ROUTER_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONF DLEP router plugin",
   .author = "Henning Rogge",
 
@@ -169,8 +178,8 @@ _cb_config_changed(void) {
   /* read configuration */
   if (cfg_schema_tobin(interface, _router_section.post,
       _router_entries, ARRAYSIZE(_router_entries))) {
-    OONF_WARN(LOG_DLEP_ROUTER, "Could not convert %s config to bin",
-        OONF_PLUGIN_GET_NAME());
+    OONF_WARN(LOG_DLEP_ROUTER, "Could not convert "
+        OONF_DLEP_ROUTER_SUBSYSTEM " config to bin");
     return;
   }
 
similarity index 94%
rename from src-plugins/dlep/router/dlep_router.h
rename to src-plugins/generic/dlep/router/dlep_router.h
index 1819f16..a9ea0ed 100644 (file)
 #include "common/common_types.h"
 #include "common/avl.h"
 #include "core/oonf_subsystem.h"
-#include "subsystems/oonf_packet_socket.h"
-#include "subsystems/oonf_stream_socket.h"
-#include "subsystems/oonf_timer.h"
 
 #include "dlep/dlep_bitmap.h"
 
+#define OONF_DLEP_ROUTER_SUBSYSTEM "dlep_router"
+
 #define LOG_DLEP_ROUTER dlep_router_subsystem.logging
 EXPORT extern struct oonf_subsystem dlep_router_subsystem;
 
@@ -47,8 +47,6 @@
 #include "common/avl_comp.h"
 #include "common/netaddr.h"
 
-#include "config/cfg_schema.h"
-#include "core/oonf_plugins.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_packet_socket.h"
@@ -47,8 +47,6 @@
 #include "common/avl_comp.h"
 #include "common/netaddr.h"
 
-#include "config/cfg_schema.h"
-#include "core/oonf_plugins.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_packet_socket.h"
similarity index 93%
rename from src-plugins/eth_listener/eth_listener.c
rename to src-plugins/generic/eth_listener/eth_listener.c
index 632b3b8..fec8d1b 100644 (file)
@@ -49,7 +49,7 @@
 
 #include "common/common_types.h"
 #include "config/cfg_schema.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_clock.h"
 #include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_layer2.h"
@@ -77,7 +77,7 @@ static struct cfg_schema_entry _eth_entries[] = {
 };
 
 static struct cfg_schema_section _eth_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_ETH_LISTENER_SUBSYSTEM,
   .cb_delta_handler = _cb_config_changed,
   .entries = _eth_entries,
   .entry_count = ARRAYSIZE(_eth_entries),
@@ -86,8 +86,17 @@ static struct cfg_schema_section _eth_section = {
 static struct _eth_config _config;
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLOCK_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+
 struct oonf_subsystem eth_listener_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_ETH_LISTENER_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONF ethernet listener plugin",
   .author = "Henning Rogge",
 
@@ -195,8 +204,8 @@ static void
 _cb_config_changed(void) {
   if (cfg_schema_tobin(&_config, _eth_section.post,
       _eth_entries, ARRAYSIZE(_eth_entries))) {
-    OONF_WARN(LOG_ETH, "Could not convert %s config to bin",
-        OONF_PLUGIN_GET_NAME());
+    OONF_WARN(LOG_ETH, "Could not convert "
+        OONF_ETH_LISTENER_SUBSYSTEM " config to bin");
     return;
   }
 
similarity index 97%
rename from src-plugins/eth_listener/eth_listener.h
rename to src-plugins/generic/eth_listener/eth_listener.h
index 49ffbd4..80aad9a 100644 (file)
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_ETH_LISTENER_SUBSYSTEM "eth_listener"
+
 #define LOG_ETH eth_listener_subsystem.logging
 EXPORT extern struct oonf_subsystem eth_listener_subsystem;
 
similarity index 95%
rename from src-plugins/httptelnet/httptelnet.c
rename to src-plugins/generic/httptelnet/httptelnet.c
index 17cb69e..7d6f13d 100644 (file)
@@ -45,7 +45,6 @@
 #include "common/netaddr_acl.h"
 #include "config/cfg_schema.h"
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
 #include "core/oonf_subsystem.h"
 #include "core/oonf_cfg.h"
 #include "subsystems/oonf_http.h"
@@ -75,15 +74,22 @@ static struct cfg_schema_entry _httptelnet_entries[] = {
 };
 
 static struct cfg_schema_section _httptelnet_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_HTTPTELNET_SUBSYSTEM,
   .cb_delta_handler = _cb_config_changed,
   .entries = _httptelnet_entries,
   .entry_count = ARRAYSIZE(_httptelnet_entries),
 };
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_HTTP_SUBSYSTEM,
+  OONF_TELNET_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_httptelnet_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_HTTPTELNET_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONFD http2telnet bridge plugin",
   .author = "Henning Rogge",
 
@@ -165,7 +171,7 @@ _cb_config_changed(void) {
   if (cfg_schema_tobin(&_http_site_handler, _httptelnet_section.post,
       _httptelnet_entries, ARRAYSIZE(_httptelnet_entries))) {
     OONF_WARN(LOG_HTTPTELNET, "Could not convert %s config to bin",
-        OONF_PLUGIN_GET_NAME());
+        OONF_HTTPTELNET_SUBSYSTEM);
     return;
   }
 
similarity index 97%
rename from src-plugins/httptelnet/httptelnet.h
rename to src-plugins/generic/httptelnet/httptelnet.h
index 77d48e8..350c5ef 100644 (file)
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_HTTPTELNET_SUBSYSTEM "httptelnet"
+
 #define LOG_HTTPTELNET oonf_httptelnet_subsystem.logging
 EXPORT extern struct oonf_subsystem oonf_httptelnet_subsystem;
 
 
 #include "config/cfg_schema.h"
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_clock.h"
-#include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_layer2.h"
-#include "subsystems/oonf_telnet.h"
 #include "subsystems/oonf_timer.h"
 
 #include "layer2_generator/layer2_generator.h"
@@ -99,15 +97,23 @@ static struct cfg_schema_entry _l2gen_entries[] = {
 };
 
 static struct cfg_schema_section _l2gen_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_L2GEN_SUBSYSTEM,
   .cb_delta_handler = _cb_config_changed,
   .entries = _l2gen_entries,
   .entry_count = ARRAYSIZE(_l2gen_entries),
 };
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLOCK_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+
 struct oonf_subsystem layer2_generator_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_L2GEN_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONF layer2-generator plugin",
   .author = "Henning Rogge",
 
@@ -209,7 +215,7 @@ _cb_config_changed(void) {
   if (cfg_schema_tobin(&_l2gen_config, _l2gen_section.post,
       _l2gen_entries, ARRAYSIZE(_l2gen_entries))) {
     OONF_WARN(LOG_L2GEN, "Could not convert %s section to bin",
-        OONF_PLUGIN_GET_NAME());
+        OONF_L2GEN_SUBSYSTEM);
     return;
   }
 
@@ -44,6 +44,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_L2GEN_SUBSYSTEM "layer2_generator"
+
 #define LOG_L2GEN layer2_generator_subsystem.logging
 EXPORT extern struct oonf_subsystem layer2_generator_subsystem;
 
similarity index 96%
rename from src-plugins/layer2info/layer2info.c
rename to src-plugins/generic/layer2info/layer2info.c
index c2419ea..716c439 100644 (file)
@@ -49,9 +49,8 @@
 #include "common/template.h"
 
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_clock.h"
-#include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_layer2.h"
 #include "subsystems/oonf_telnet.h"
 #include "subsystems/oonf_viewer.h"
@@ -206,13 +205,22 @@ static struct oonf_viewer_template _templates[] = {
 
 /* telnet command of this plugin */
 static struct oonf_telnet_command _telnet_commands[] = {
-    TELNET_CMD(OONF_PLUGIN_GET_NAME(), _cb_layer2info,
+    TELNET_CMD(OONF_LAYER2INFO_SUBSYSTEM, _cb_layer2info,
         "", .help_handler = _cb_layer2info_help),
 };
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLOCK_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_TELNET_SUBSYSTEM,
+  OONF_VIEWER_SUBSYSTEM,
+};
+
 struct oonf_subsystem olsrv2_layer2info_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_LAYER2INFO_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OLSRv2 layer2 info plugin",
   .author = "Henning Rogge",
   .init = _init,
@@ -286,7 +294,7 @@ _cb_layer2info(struct oonf_telnet_data *con) {
   }
 
   if (con->parameter == NULL || *con->parameter == 0) {
-    abuf_puts(con->out, "Error, '" OONF_PLUGIN_GET_NAME() "' needs a parameter\n");
+    abuf_puts(con->out, "Error, '" OONF_LAYER2INFO_SUBSYSTEM "' needs a parameter\n");
   }
   abuf_appendf(con->out, "Wrong parameter in command: %s\n", con->parameter);
   return TELNET_RESULT_ACTIVE;
@@ -302,7 +310,7 @@ _cb_layer2info_help(struct oonf_telnet_data *con) {
   const char *next;
 
   /* skip the layer2info command */
-  next = str_hasnextword(con->parameter, OONF_PLUGIN_GET_NAME());
+  next = str_hasnextword(con->parameter, OONF_LAYER2INFO_SUBSYSTEM);
 
   /* print out own help text */
   abuf_puts(con->out, "Layer2 database information command\n");
similarity index 97%
rename from src-plugins/layer2info/layer2info.h
rename to src-plugins/generic/layer2info/layer2info.h
index e46035a..c999f43 100644 (file)
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_LAYER2INFO_SUBSYSTEM "layer2info"
+
 #define LOG_LAYER2INFO oonf_layer2info_subsystem.logging
 EXPORT extern struct oonf_subsystem oonf_layer2info_subsystem;
 
similarity index 97%
rename from src-plugins/link_config/link_config.c
rename to src-plugins/generic/link_config/link_config.c
index 32db7a6..73a5dc4 100644 (file)
@@ -45,7 +45,7 @@
 #include "config/cfg_schema.h"
 #include "config/cfg_validate.h"
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_layer2.h"
@@ -97,8 +97,16 @@ static struct cfg_schema_section _link_config_section = {
   .entry_count = ARRAYSIZE(_link_config_if_entries),
 };
 
+/* declare subsystem */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+};
 struct oonf_subsystem oonf_link_config_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_LINK_CONFIG_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .init = _init,
   .cleanup = _cleanup,
 
similarity index 97%
rename from src-plugins/link_config/link_config.h
rename to src-plugins/generic/link_config/link_config.h
index 52cbe15..fd3292b 100644 (file)
@@ -45,6 +45,7 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_LINK_CONFIG_SUBSYSTEM "link_config"
 #define LOG_LINK_CONFIG oonf_link_config_subsystem.logging
 EXPORT extern struct oonf_subsystem oonf_link_config_subsystem;
 
@@ -63,7 +63,6 @@
 #include "config/cfg.h"
 #include "config/cfg_schema.h"
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_interface.h"
@@ -172,7 +171,7 @@ static struct cfg_schema_entry _nl80211_entries[] = {
 };
 
 static struct cfg_schema_section _nl80211_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_NL80211_LISTENER_SUBSYSTEM,
   .cb_delta_handler = _cb_config_changed,
   .entries = _nl80211_entries,
   .entry_count = ARRAYSIZE(_nl80211_entries),
@@ -182,8 +181,18 @@ static struct cfg_schema_section _nl80211_section = {
 static struct _nl80211_config _config;
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_OS_SYSTEM_SUBSYSTEM,
+};
+
 struct oonf_subsystem nl80211_listener_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_NL80211_LISTENER_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONF nl80211 listener plugin",
   .author = "Henning Rogge",
 
@@ -586,8 +595,8 @@ _cb_config_changed(void) {
 
   if (cfg_schema_tobin(&_config, _nl80211_section.post,
       _nl80211_entries, ARRAYSIZE(_nl80211_entries))) {
-    OONF_WARN(LOG_NL80211, "Could not convert %s config to bin",
-        OONF_PLUGIN_GET_NAME());
+    OONF_WARN(LOG_NL80211, "Could not convert "
+        OONF_NL80211_LISTENER_SUBSYSTEM " config to bin");
     return;
   }
 
@@ -47,6 +47,8 @@
 #include "subsystems/oonf_interface.h"
 #include "subsystems/oonf_layer2.h"
 
+#define OONF_NL80211_LISTENER_SUBSYSTEM "nl80211_listener"
+
 struct nl80211_if {
   char name[IF_NAMESIZE];
 
 #include "common/netaddr.h"
 #include "common/netaddr_acl.h"
 #include "config/cfg_schema.h"
+#include "core/oonf_cfg.h"
 #include "core/oonf_logging.h"
-#include "core/oonf_plugins.h"
 #include "core/oonf_subsystem.h"
-
-#include "core/oonf_cfg.h"
 #include "subsystems/oonf_telnet.h"
 
 #include "plugin_controller/plugin_controller.h"
@@ -77,7 +75,7 @@ static struct cfg_schema_entry _plugin_controller_entries[] = {
 };
 
 static struct cfg_schema_section _plugin_controller_section = {
-  .type = OONF_PLUGIN_GET_NAME(),
+  .type = OONF_PLUGIN_CONTROLLER_SUBSYSTEM,
   .cb_delta_handler = _cb_config_changed,
   .entries = _plugin_controller_entries,
   .entry_count = ARRAYSIZE(_plugin_controller_entries),
@@ -86,8 +84,14 @@ static struct cfg_schema_section _plugin_controller_section = {
 struct _acl_config _config;
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_TELNET_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_plugin_controller_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
+  .name = OONF_PLUGIN_CONTROLLER_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
   .descr = "OONFD plugin controller plugin",
   .author = "Henning Rogge",
 
@@ -46,6 +46,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_PLUGIN_CONTROLLER_SUBSYSTEM "plugin_controller"
+
 #define LOG_PLUGINCTRL oonf_plugin_controller_subsystem.logging
 EXPORT extern struct oonf_subsystem oonf_plugin_controller_subsystem;
 
 #include "common/list.h"
 #include "common/netaddr.h"
 #include "common/string.h"
-
 #include "config/cfg_cmd.h"
 #include "config/cfg_db.h"
 #include "config/cfg_schema.h"
-
+#include "core/oonf_cfg.h"
 #include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
-#include "core/oonf_plugins.h"
 #include "subsystems/oonf_timer.h"
-#include "core/oonf_subsystem.h"
-#include "subsystems/os_routing.h"
-
-#include "core/oonf_cfg.h"
 #include "subsystems/oonf_telnet.h"
+#include "subsystems/os_routing.h"
 
 #include "remotecontrol/remotecontrol.h"
 
@@ -114,7 +110,7 @@ static struct cfg_schema_entry _remotecontrol_entries[] = {
 };
 
 static struct cfg_schema_section _remotecontrol_section = {
-  .type = "remotecontrol",
+  .type = OONF_REMOTECONTROL_SUBSYSTEM,
   .cb_delta_handler = _cb_config_changed,
   .entries = _remotecontrol_entries,
   .entry_count = ARRAYSIZE(_remotecontrol_entries),
@@ -123,9 +119,18 @@ static struct cfg_schema_section _remotecontrol_section = {
 static struct _remotecontrol_cfg _remotecontrol_config;
 
 /* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_TELNET_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_OS_ROUTING_SUBSYSTEM,
+};
+
 struct oonf_subsystem oonf_remotecontrol_subsystem = {
-  .name = OONF_PLUGIN_GET_NAME(),
- .descr = "OONFD remote control and debug plugin",
+  .name = OONF_REMOTECONTROL_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .descr = "OONFD remote control and debug plugin",
   .author = "Henning Rogge",
 
   .cfg_section = &_remotecontrol_section,
@@ -45,6 +45,8 @@
 #include "common/common_types.h"
 #include "core/oonf_subsystem.h"
 
+#define OONF_REMOTECONTROL_SUBSYSTEM "remotecontrol"
+
 #define LOG_REMOTECONTROL oonf_remotecontrol_subsystem.logging
 EXPORT extern struct oonf_subsystem oonf_remotecontrol_subsystem;
 
diff --git a/src-plugins/nhdp/CMakeLists.txt b/src-plugins/nhdp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ef0a682
--- /dev/null
@@ -0,0 +1,10 @@
+# add subdirectories
+add_subdirectory(auto_ll4)
+add_subdirectory(constant_metric)
+add_subdirectory(nhdpcheck)
+add_subdirectory(hysteresis_olsrv1)
+add_subdirectory(ff_dat_metric)
+add_subdirectory(mpr)
+add_subdirectory(neighbor_probing)
+add_subdirectory(nhdp)
+add_subdirectory(nhdpinfo)
diff --git a/src-plugins/nhdp/auto_ll4/CMakeLists.txt b/src-plugins/nhdp/auto_ll4/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0d58e90
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (source auto_ll4.c)
+
+# use generic plugin maker
+oonf_create_app_plugin("auto_ll4" "${source}" "")
diff --git a/src-plugins/nhdp/auto_ll4/auto_ll4.c b/src-plugins/nhdp/auto_ll4/auto_ll4.c
new file mode 100644 (file)
index 0000000..cb5cad0
--- /dev/null
@@ -0,0 +1,808 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_cfg.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "core/os_core.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_interface.h"
+#include "subsystems/oonf_timer.h"
+#include "subsystems/os_system.h"
+
+#include "nhdp/nhdp.h"
+#include "nhdp/nhdp_domain.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "auto_ll4/auto_ll4.h"
+
+/* constants and definitions */
+struct _config {
+  uint64_t startup_delay;
+};
+
+#define _MODE_DETECT "detect"
+
+struct _nhdp_if_autoll4 {
+  /* timer until next update of autogenerated ip */
+  struct oonf_timer_instance update_timer;
+
+  /* true if interface LL4 was generated by this plugin */
+  bool active;
+
+  /* true if current LL4 was generated by the plugin */
+  bool plugin_generated;
+
+  /* data structure for setting and resetting auto-configured address */
+  struct os_system_address os_addr;
+
+  /* currently configured address */
+  struct netaddr auto_ll4_addr;
+};
+
+/* prototypes */
+static int _init(void);
+static void _initiate_shutdown(void);
+static void _cleanup(void);
+
+static void _cb_add_nhdp_interface(void *);
+static void _cb_remove_nhdp_interface(void *);
+static void _cb_address_finished(struct os_system_address *, int);
+static void _cb_update_timer(void *);
+static int _get_current_if_ipv4_addresscount(
+    struct oonf_interface_data *ifdata,
+    struct netaddr *ll4_addr, struct netaddr *current_ll4);
+static void _generate_default_address(
+    struct _nhdp_if_autoll4 *auto_ll4, const struct netaddr *ipv6_ll);
+
+static void _commit_address(struct _nhdp_if_autoll4 *auto_ll4
+    , struct netaddr *addr, bool set);
+uint16_t _calculate_host_part(const struct netaddr *addr);
+static bool _is_address_collision(
+    struct netaddr *auto_ll4, struct netaddr *addr);
+static bool _nhdp_if_has_collision(
+    struct nhdp_interface *nhdp_if, struct netaddr *addr);
+static void _cb_ifaddr_change(void *);
+static void _cb_laddr_change(void *);
+static void _cb_2hop_change(void *);
+static void _cb_ll4_cfg_changed(void);
+static void _cb_if_cfg_changed(void);
+
+/* plugin declaration */
+static struct cfg_schema_entry _interface_entries[] = {
+  CFG_MAP_BOOL(_nhdp_if_autoll4, active, "auto_ll4", "true",
+      "Controls autogeneration of IPv4 linklocal IPs on interface."),
+};
+
+static struct cfg_schema_section _interface_section = {
+  .type = CFG_INTERFACE_SECTION,
+  .mode = CFG_INTERFACE_SECTION_MODE,
+  .cb_delta_handler = _cb_if_cfg_changed,
+  .entries = _interface_entries,
+  .entry_count = ARRAYSIZE(_interface_entries),
+};
+
+static struct cfg_schema_entry _auto_ll4_entries[] = {
+  CFG_MAP_CLOCK(_config, startup_delay, "startup", "10",
+      "Startup time until first auto-configuredIPv4 linklocal should be selected."),
+};
+
+static struct cfg_schema_section _auto_ll4_section = {
+  .type = OONF_AUTO_LL4_SUBSYSTEM,
+  .mode = CFG_SSMODE_UNNAMED,
+  .cb_delta_handler = _cb_ll4_cfg_changed,
+  .entries = _auto_ll4_entries,
+  .entry_count = ARRAYSIZE(_auto_ll4_entries),
+  .next_section = &_interface_section,
+};
+
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_OS_SYSTEM_SUBSYSTEM,
+  OONF_NHDP_SUBSYSTEM,
+};
+struct oonf_subsystem olsrv2_auto_ll4_subsystem = {
+  .name = OONF_AUTO_LL4_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .descr = "OLSRv2 Automatic IPv4 Linklayer IP generation plugin",
+  .author = "Henning Rogge",
+
+  .cfg_section = &_auto_ll4_section,
+
+  .init = _init,
+  .cleanup = _cleanup,
+  .initiate_shutdown = _initiate_shutdown,
+};
+DECLARE_OONF_PLUGIN(olsrv2_auto_ll4_subsystem);
+
+/* timer for handling new NHDP neighbors */
+static struct oonf_timer_class _startup_timer_info = {
+  .name = "Initial delay until first IPv4 linklocal IPs are generated",
+  .callback = _cb_update_timer,
+  .periodic = false,
+};
+
+/* NHDP interface extension/listener */
+static struct oonf_class_extension _nhdp_if_extenstion = {
+  .ext_name = "auto ll4 generation",
+  .class_name = NHDP_CLASS_INTERFACE,
+  .size = sizeof(struct _nhdp_if_autoll4),
+
+  .cb_add = _cb_add_nhdp_interface,
+  .cb_remove = _cb_remove_nhdp_interface,
+};
+
+/* NHDP interface address listener */
+static struct oonf_class_extension _nhdp_ifaddr_listener = {
+  .ext_name = "auto ll4 generation",
+  .class_name = NHDP_CLASS_INTERFACE_ADDRESS,
+
+  .cb_add = _cb_ifaddr_change,
+  .cb_remove = _cb_ifaddr_change,
+};
+
+/* NHDP link address listener */
+static struct oonf_class_extension _nhdp_laddr_listener = {
+  .ext_name = "auto ll4 laddr listener",
+  .class_name = NHDP_CLASS_LINK_ADDRESS,
+
+  .cb_add = _cb_laddr_change,
+  .cb_remove = _cb_laddr_change,
+};
+
+/* NHDP twohop listener */
+static struct oonf_class_extension _nhdp_2hop_listener = {
+  .ext_name = "auto ll4 twohop listener",
+  .class_name = NHDP_CLASS_LINK_2HOP,
+
+  .cb_add = _cb_2hop_change,
+  .cb_remove = _cb_2hop_change,
+};
+
+/* global variables */
+static uint64_t _ll4_startup_delay = 10*1000;
+
+/**
+ * Initialize plugin
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_init(void) {
+  if (oonf_class_extension_add(&_nhdp_if_extenstion)) {
+    OONF_WARN(LOG_AUTO_LL4, "Cannot allocate extension for NHDP interface data");
+    return -1;
+  }
+
+  oonf_class_extension_add(&_nhdp_ifaddr_listener);
+  oonf_class_extension_add(&_nhdp_laddr_listener);
+  oonf_class_extension_add(&_nhdp_2hop_listener);
+  oonf_timer_add(&_startup_timer_info);
+  return 0;
+}
+
+/**
+ * Initiate cleanup of plugin.
+ */
+static void
+_initiate_shutdown(void) {
+  struct nhdp_interface *nhdp_if;
+
+  avl_for_each_element(&nhdp_interface_tree, nhdp_if, _node) {
+    OONF_DEBUG(LOG_AUTO_LL4, "initiate cleanup if: %s",
+        nhdp_interface_get_coreif(nhdp_if)->data.name);
+    _cb_remove_nhdp_interface(nhdp_if);
+  }
+  oonf_class_extension_remove(&_nhdp_if_extenstion);
+  oonf_class_extension_remove(&_nhdp_2hop_listener);
+  oonf_class_extension_remove(&_nhdp_laddr_listener);
+  oonf_class_extension_remove(&_nhdp_ifaddr_listener);
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+  oonf_timer_remove(&_startup_timer_info);
+}
+
+/**
+ * Callback triggered when a new NHDP interface is added to the database
+ * @param ptr pointer to NHDP interface
+ */
+static void
+_cb_add_nhdp_interface(void *ptr) {
+  struct nhdp_interface *nhdp_if = ptr;
+  struct _nhdp_if_autoll4 *auto_ll4;
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  /* initialize static part of routing data */
+  auto_ll4->os_addr.cb_finished = _cb_address_finished;
+  auto_ll4->os_addr.if_index = nhdp_interface_get_coreif(nhdp_if)->data.index;
+  auto_ll4->os_addr.scope = OS_ADDR_SCOPE_LINK;
+
+  /* activate update_timer delay timer */
+  auto_ll4->update_timer.class = &_startup_timer_info;
+  auto_ll4->update_timer.cb_context = nhdp_if;
+  oonf_timer_set(&auto_ll4->update_timer, _ll4_startup_delay);
+}
+
+/**
+ * Callback triggered when a NHDP interface is removed from the database
+ * @param ptr pointer to NHDP interface
+ */
+static void
+_cb_remove_nhdp_interface(void *ptr) {
+  struct nhdp_interface *nhdp_if = ptr;
+  struct _nhdp_if_autoll4 *auto_ll4;
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  /* stop running address setting feedback */
+  auto_ll4->os_addr.cb_finished = NULL;
+  os_system_ifaddr_interrupt(&auto_ll4->os_addr);
+
+  /* cleanup address if necessary */
+  auto_ll4->active = false;
+  _cb_update_timer(nhdp_if);
+
+  /* stop update timer */
+  oonf_timer_stop(&auto_ll4->update_timer);
+}
+
+/**
+ * Callback triggered when the kernel acknowledged that an address has
+ * been set on an interface (or not, because an error happened)
+ * @param os_addr pointer to address parameters
+ * @param error 0 if address was set, otherwise an error happened
+ */
+static void
+_cb_address_finished(struct os_system_address *os_addr, int error) {
+  struct _nhdp_if_autoll4 *auto_ll4;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+  char ibuf[IF_NAMESIZE];
+#endif
+
+  /* get auto linklayer extension */
+  auto_ll4 = container_of(os_addr, typeof(*auto_ll4), os_addr);
+
+  OONF_DEBUG(LOG_AUTO_LL4, "Got feedback from netlink for %s address %s on if %s: %s (%d)",
+      os_addr->set ? "setting" : "resetting",
+          netaddr_to_string(&nbuf, &os_addr->address),
+          if_indextoname(os_addr->if_index, ibuf),
+          strerror(error), error);
+
+  if (error) {
+    if ((os_addr->set && error != EEXIST)
+        || (!os_addr->set && error != EADDRNOTAVAIL)) {
+      /* try again */
+      oonf_timer_set(&auto_ll4->update_timer, 1000);
+      return;
+    }
+  }
+}
+
+/**
+ * Callback triggered when an address changes on a NHDP interface
+ * @param ptr pointer to NHDP interface
+ */
+static void
+_cb_ifaddr_change(void *ptr) {
+  struct nhdp_interface_addr *ifaddr = ptr;
+  struct nhdp_interface *nhdp_if;
+  struct _nhdp_if_autoll4 *auto_ll4;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  nhdp_if = ifaddr->interf;
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
+    /* request delayed address check */
+    oonf_timer_set(&auto_ll4->update_timer, 1);
+
+    OONF_DEBUG(LOG_AUTO_LL4, "Interface address changed: %s",
+        netaddr_to_string(&nbuf, &ifaddr->if_addr));
+  }
+}
+
+/**
+ * Callback triggered when a link address of a NHDP neighbor changes
+ * @param ptr pointer to NHDP link address
+ */
+static void
+_cb_laddr_change(void *ptr) {
+  struct nhdp_laddr *laddr = ptr;
+  struct nhdp_interface *nhdp_if;
+  struct _nhdp_if_autoll4 *auto_ll4;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  nhdp_if = laddr->link->local_if;
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
+    /* request delayed address check */
+    oonf_timer_set(&auto_ll4->update_timer, 1);
+
+    OONF_DEBUG(LOG_AUTO_LL4, "Link address changed: %s",
+        netaddr_to_string(&nbuf, &laddr->link_addr));
+  }
+}
+
+/**
+ * Callback triggered when a two-hop address of a NHDP neighbor changes
+ * @param ptr pointer to NHDP two-hop address
+ */
+static void
+_cb_2hop_change(void *ptr) {
+  struct nhdp_l2hop *l2hop = ptr;
+  struct nhdp_interface *nhdp_if;
+  struct _nhdp_if_autoll4 *auto_ll4;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  nhdp_if = l2hop->link->local_if;
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
+    /* request delayed address check */
+    oonf_timer_set(&auto_ll4->update_timer, 1);
+
+    OONF_DEBUG(LOG_AUTO_LL4, "2Hop address changed: %s",
+        netaddr_to_string(&nbuf, &l2hop->twohop_addr));
+  }
+}
+
+/**
+ * Callback triggered when the plugin should check if the autoconfigured
+ * address is still okay.
+ * @param ptr pointer to NHDP interface
+ */
+static void
+_cb_update_timer(void *ptr) {
+  struct nhdp_interface *nhdp_if = ptr;
+  struct oonf_interface_data *ifdata;
+  struct _nhdp_if_autoll4 *auto_ll4;
+  struct netaddr current_ll4;
+  struct netaddr_str nbuf;
+  int count;
+  uint16_t hash;
+
+  /* get pointer to interface data */
+  ifdata = &(nhdp_interface_get_coreif(nhdp_if)->data);
+
+  /* ignore loopback */
+  if (ifdata->loopback || !ifdata->up) {
+    OONF_DEBUG(LOG_AUTO_LL4, "Ignore interface %s: its loopback or down",
+        ifdata->name);
+    return;
+  }
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  /* query current interface status */
+  count = _get_current_if_ipv4_addresscount(ifdata, &current_ll4, &auto_ll4->auto_ll4_addr);
+
+  if (!oonf_rfc5444_is_interface_active(nhdp_if->rfc5444_if.interface, AF_INET6)) {
+    if (auto_ll4->plugin_generated) {
+      /* remove our configured address, this interface does not support dualstack */
+      _commit_address(auto_ll4, &current_ll4, false);
+      OONF_DEBUG(LOG_AUTO_LL4,
+          "Remove LL4 address, interface is not using NHDP on IPv6");
+    }
+    OONF_DEBUG(LOG_AUTO_LL4,
+        "Done (interface %s is not using NHDP on IPv6)", ifdata->name);
+    return;
+  }
+
+  if (!auto_ll4->active) {
+    if (auto_ll4->plugin_generated && count == 1
+        && netaddr_cmp(&current_ll4, &auto_ll4->auto_ll4_addr) == 0) {
+      /* remove our configured address, the user set a different one */
+      _commit_address(auto_ll4, &current_ll4, false);
+      OONF_DEBUG(LOG_AUTO_LL4, "Remove LL4, user has selected his own address");
+    }
+    OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s is not active)", ifdata->name);
+    return;
+  }
+
+  if (count > 1) {
+    if (auto_ll4->plugin_generated &&
+        netaddr_cmp(&current_ll4, &auto_ll4->auto_ll4_addr) == 0) {
+      /* remove our configured address, the user set a different one */
+      _commit_address(auto_ll4, &current_ll4, false);
+      OONF_DEBUG(LOG_AUTO_LL4, "Remove LL4, user has selected his own address");
+    }
+    OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s has additional addresses)", ifdata->name);
+    return;
+  }
+
+  if (count == 1) {
+    if (netaddr_get_address_family(&current_ll4) == AF_UNSPEC) {
+      /* do nothing, user set a non-LL interface IP */
+      OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s has non-ll ipv4)", ifdata->name);
+      return;
+    }
+
+    /* copy the current IP to the setting variable */
+    memcpy(&auto_ll4->auto_ll4_addr, &current_ll4, sizeof(current_ll4));
+  }
+
+  if (netaddr_get_address_family(&auto_ll4->auto_ll4_addr) == AF_UNSPEC) {
+    /* try our default IP first */
+    _generate_default_address(auto_ll4, ifdata->linklocal_v6_ptr);
+  }
+
+  while (_nhdp_if_has_collision(nhdp_if, &auto_ll4->auto_ll4_addr)) {
+    /* roll up a random address */
+    hash = htons((os_core_random() % (256 * 254)) + 256);
+    netaddr_create_host_bin(&auto_ll4->auto_ll4_addr,
+        &NETADDR_IPV4_LINKLOCAL, &hash, sizeof(hash));
+  }
+
+  if (netaddr_cmp(&auto_ll4->auto_ll4_addr, &current_ll4) == 0) {
+    /* nothing to do */
+    OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s already has ll %s)",
+        ifdata->name, netaddr_to_string(&nbuf, &current_ll4));
+    return;
+  }
+
+  if (netaddr_get_address_family(&current_ll4) != AF_UNSPEC) {
+    /* remove current ipv4 linklocal address */
+    OONF_DEBUG(LOG_AUTO_LL4, "Remove old LL4 %s",
+        netaddr_to_string(&nbuf, &current_ll4));
+    _commit_address(auto_ll4, &current_ll4, false);
+  }
+  else {
+    /* set new ipv4 linklocal address */
+    OONF_DEBUG(LOG_AUTO_LL4, "Set new LL4 %s",
+        netaddr_to_string(&nbuf, &auto_ll4->auto_ll4_addr));
+    _commit_address(auto_ll4, &auto_ll4->auto_ll4_addr, true);
+  }
+}
+
+/**
+ * Generate a new auto-configured address on an interface
+ * @param nhdp_if pointer to NHDP interface
+ */
+static void
+_generate_default_address(struct _nhdp_if_autoll4 *auto_ll4, const struct netaddr *ipv6_ll) {
+  uint16_t host_part;
+  struct netaddr_str nbuf1, nbuf2;
+
+  if (netaddr_get_address_family(ipv6_ll) == AF_UNSPEC) {
+    /* no ipv6 linklocal address */
+    netaddr_invalidate(&auto_ll4->auto_ll4_addr);
+  }
+
+  host_part = _calculate_host_part(ipv6_ll);
+
+  /*
+   * generate the address between
+   * 169.254.1.0 and 169.254.254.255
+   */
+  netaddr_create_host_bin(&auto_ll4->auto_ll4_addr, &NETADDR_IPV4_LINKLOCAL,
+      &host_part, sizeof(host_part));
+
+  OONF_DEBUG(LOG_AUTO_LL4, "IPv6 ll %s => IPv4 ll %s",
+      netaddr_to_string(&nbuf1, ipv6_ll),
+      netaddr_to_string(&nbuf2, &auto_ll4->auto_ll4_addr));
+}
+
+/**
+ * Get the current number of IPv4 addresses of an interface and
+ * copy an IPv4 link-local address if set.
+ * @param ifdata pointer to interface data
+ * @param ll4_addr return buffer for link-local address
+ * @param current_ll4 current link-local address, this will be returned
+ *   if set, even if multiple ipv4 link-local addresses are present
+ * @return number of IPv4 addresses on interface
+ */
+static int
+_get_current_if_ipv4_addresscount(struct oonf_interface_data *ifdata,
+    struct netaddr *ll4_addr, struct netaddr *current_ll4) {
+  struct netaddr *ifaddr;
+  bool match;
+  int count;
+  size_t i;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  /* reset counter */
+  count = 0;
+  netaddr_invalidate(ll4_addr);
+  match = false;
+
+  for (i=0; i<ifdata->addrcount; i++) {
+    /* look through interface IPs */
+    ifaddr = &ifdata->addresses[i];
+
+    OONF_DEBUG(LOG_AUTO_LL4, "Interface %s has address %s",
+        ifdata->name, netaddr_to_string(&nbuf, ifaddr));
+
+    if (netaddr_get_address_family(ifaddr) == AF_INET) {
+      /* count IPv4 addresses */
+      count++;
+
+      /* copy one IPv4 link-local address, if possible the current one */
+      if (!match && netaddr_is_in_subnet(&NETADDR_IPV4_LINKLOCAL, ifaddr)) {
+        memcpy(ll4_addr, &ifdata->addresses[i], sizeof(*ll4_addr));
+
+        if (netaddr_cmp(ifaddr, current_ll4) == 0) {
+          match = true;
+        }
+      }
+    }
+  }
+
+  return count;
+}
+
+/**
+ * Set/reset an address on a NHDP interface
+ * @param auto_ll4 pointer to data structure for auto-configured
+ * addresses on a NHDP interface
+ */
+static void
+_commit_address(struct _nhdp_if_autoll4 *auto_ll4, struct netaddr *addr, bool set) {
+#ifdef OONF_LOG_INFO
+  struct netaddr_str nbuf;
+  char ibuf[IF_NAMESIZE];
+#endif
+
+  memcpy(&auto_ll4->os_addr.address, addr, sizeof(*addr));
+  auto_ll4->os_addr.set = set;
+
+  OONF_INFO(LOG_AUTO_LL4, "%s address %s on interface %s",
+      auto_ll4->os_addr.set ? "Set" : "Remove",
+      netaddr_to_string(&nbuf, &auto_ll4->os_addr.address),
+      if_indextoname(auto_ll4->os_addr.if_index, ibuf));
+
+  /* remember if the plugin set/reset the address */
+  auto_ll4->plugin_generated = set;
+
+  /* set prefix length */
+  netaddr_set_prefix_length(&auto_ll4->os_addr.address, 16);
+
+  /* call operation system */
+  os_system_ifaddr_set(&auto_ll4->os_addr);
+}
+
+/**
+ * Checks if an address would collide with any neighbor on a
+ * NHDP interface, both one- and two-hop.
+ * @param nhdp_if pointer to NHDP interface
+ * @param addr pointer to address that might collide
+ * @return true if address or hash collides with known neighbor,
+ *   false otherwise
+ */
+static bool
+_nhdp_if_has_collision(struct nhdp_interface *nhdp_if, struct netaddr *addr) {
+  struct nhdp_link *lnk;
+  struct nhdp_laddr *laddr;
+  struct nhdp_l2hop *l2hop;
+
+  list_for_each_element(&nhdp_if->_links, lnk, _if_node) {
+    /* check for collision with one-hop neighbor */
+    avl_for_each_element(&lnk->_addresses, laddr, _link_node) {
+      if (_is_address_collision(addr, &laddr->link_addr)) {
+        return true;
+      }
+    }
+
+    avl_for_each_element(&lnk->_2hop, l2hop, _link_node) {
+      if (_is_address_collision(addr, &l2hop->twohop_addr)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+/**
+ * Check if an auto-configured address has a collision
+ * @param auto_ll4 pointer to data structure for auto-configured
+ * @param addr address that could collide with auto-configured IP
+ * @return true if address collides, false otherwise
+ */
+static bool
+_is_address_collision(struct netaddr *auto_ll4, struct netaddr *addr) {
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf1, nbuf2;
+#endif
+  uint16_t hostpart;
+  const char *ptr;
+
+  OONF_DEBUG(LOG_AUTO_LL4, "Check %s for collision with address %s",
+      netaddr_to_string(&nbuf1, auto_ll4), netaddr_to_string(&nbuf2, addr));
+
+  if (netaddr_get_address_family(addr) == AF_INET) {
+    if (netaddr_cmp(auto_ll4, addr) == 0) {
+      OONF_DEBUG(LOG_AUTO_LL4, "Collision with address");
+      return true;
+    }
+  }
+  else {
+    hostpart = _calculate_host_part(addr);
+    ptr = netaddr_get_binptr(auto_ll4);
+    if (memcmp(ptr+2, &hostpart, 2) == 0) {
+      OONF_DEBUG(LOG_AUTO_LL4, "Collision with hashed IPv6!");
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/**
+ * Calculates host part of an auto-configured address
+ * based on a hash value
+ * @param addr address that should be hashed
+ * @return number between 256 (.1.0) and 65279 (.254.255)
+ */
+uint16_t
+_calculate_host_part(const struct netaddr *addr)
+{
+  uint32_t hash, i;
+  const char *key;
+  size_t len;
+
+  key = netaddr_get_binptr(addr);
+  len = netaddr_get_binlength(addr);
+
+  /*
+   * step 1: calculate Jenkins hash
+   *
+   * This is no cryptographic secure has, it doesn't need
+   * to be. Its just to make sure all 6 byte of the MAC
+   * address are the source of the two-byte host part
+   * of the auto-configuredIP.
+   */
+  for(hash = i = 0; i < len; ++i)
+  {
+    hash += key[i];
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+  }
+  hash += (hash << 3);
+  hash ^= (hash >> 11);
+  hash += (hash << 15);
+
+  /* step 2: calculate host part of linklocal address */
+  return htons((hash % (254 * 256)) + 256);
+}
+
+/**
+ * Callback triggered when plugin configuration changes
+ */
+static void
+_cb_ll4_cfg_changed(void) {
+  struct nhdp_interface *nhdp_if;
+  struct _nhdp_if_autoll4 *auto_ll4;
+  struct _config cfg;
+
+  memset(&cfg, 0, sizeof(cfg));
+  if (cfg_schema_tobin(&cfg, _auto_ll4_section.post,
+      _auto_ll4_entries, ARRAYSIZE(_auto_ll4_entries))) {
+    OONF_WARN(LOG_AUTO_LL4, "Cannot convert plugin configuration.");
+    return;
+  }
+
+  if (cfg.startup_delay == _ll4_startup_delay) {
+    return;
+  }
+
+  avl_for_each_element(&nhdp_interface_tree, nhdp_if, _node) {
+    /* get auto linklayer extension */
+    auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+    /* fix update_timer timer if still running */
+    if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
+      oonf_timer_set(&auto_ll4->update_timer, _ll4_startup_delay);
+    }
+  }
+}
+
+/**
+ * Plugin triggered when interface auto-configuration parameter changes
+ */
+static void
+_cb_if_cfg_changed(void) {
+  struct _nhdp_if_autoll4 *auto_ll4;
+  struct nhdp_interface *nhdp_if;
+
+  /* get interface */
+  nhdp_if = nhdp_interface_get(_interface_section.section_name);
+
+  if (_interface_section.post == NULL) {
+    /* section was removed */
+    if (nhdp_if != NULL) {
+      /* decrease nhdp_interface refcount */
+      nhdp_interface_remove(nhdp_if);
+    }
+    return;
+  }
+
+  if (nhdp_if == NULL) {
+    /* increase nhdp_interface refcount */
+    nhdp_if = nhdp_interface_add(_interface_section.section_name);
+  }
+
+  /* get auto linklayer extension */
+  auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
+
+  /* get configuration */
+  if (cfg_schema_tobin(auto_ll4, _interface_section.post,
+      _interface_entries, ARRAYSIZE(_interface_entries))) {
+    return;
+  }
+
+  if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
+    /* activate delayed update */
+    oonf_timer_set(&auto_ll4->update_timer, 1);
+  }
+}
diff --git a/src-plugins/nhdp/auto_ll4/auto_ll4.h b/src-plugins/nhdp/auto_ll4/auto_ll4.h
new file mode 100644 (file)
index 0000000..ad2cf15
--- /dev/null
@@ -0,0 +1,54 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef AUTO_LL4_H_
+#define AUTO_LL4_H_
+
+#include "common/common_types.h"
+#include "core/oonf_subsystem.h"
+
+/* definitions and constants */
+#define OONF_AUTO_LL4_SUBSYSTEM "auto_ll4"
+
+#define LOG_AUTO_LL4 olsrv2_auto_ll4_subsystem.logging
+EXPORT extern struct oonf_subsystem olsrv2_auto_ll4_subsystem;
+
+#endif /* AUTO_LL4_H_ */
diff --git a/src-plugins/nhdp/constant_metric/CMakeLists.txt b/src-plugins/nhdp/constant_metric/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c49c8cc
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (source constant_metric.c)
+
+# use generic plugin maker
+oonf_create_app_plugin("constant_metric" "${source}" "")
diff --git a/src-plugins/nhdp/constant_metric/constant_metric.c b/src-plugins/nhdp/constant_metric/constant_metric.c
new file mode 100644 (file)
index 0000000..ab5ad0a
--- /dev/null
@@ -0,0 +1,375 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "config/cfg_schema.h"
+#include "config/cfg_validate.h"
+#include "core/oonf_cfg.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "rfc5444/rfc5444.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_interface.h"
+#include "subsystems/oonf_timer.h"
+
+#include "nhdp/nhdp.h"
+#include "nhdp/nhdp_domain.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "constant_metric/constant_metric.h"
+
+/* constants and definitions */
+#define CFG_LINK_ENTRY "link"
+
+struct _linkcost {
+  struct avl_node _node;
+
+  char if_name[IF_NAMESIZE];
+  struct netaddr neighbor;
+  uint32_t cost;
+};
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+
+static void _cb_link_added(void *);
+static void _cb_set_linkcost(void *);
+
+static int _avlcmp_linkcost(const void *, const void *);
+
+static int _cb_validate_link(const struct cfg_schema_entry *entry,
+      const char *section_name, const char *value, struct autobuf *out);
+static void _cb_cfg_changed(void);
+
+/* plugin declaration */
+static struct cfg_schema_entry _constant_entries[] = {
+  _CFG_VALIDATE(CFG_LINK_ENTRY, "", "Defines the static cost to the link to a neighbor."
+      " Value consists of the originator address followed by the link cost",
+      .cb_validate = _cb_validate_link, .list = true),
+};
+
+static struct cfg_schema_section _constant_section = {
+  .type = OONF_CONSTANT_METRIC_SUBSYSTEM,
+  .mode = CFG_SSMODE_NAMED_WITH_DEFAULT,
+  .def_name = OONF_INTERFACE_WILDCARD,
+  .cb_delta_handler = _cb_cfg_changed,
+  .entries = _constant_entries,
+  .entry_count = ARRAYSIZE(_constant_entries),
+};
+
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_INTERFACE_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_NHDP_SUBSYSTEM,
+};
+struct oonf_subsystem olsrv2_constant_metric_subsystem = {
+  .name = OONF_CONSTANT_METRIC_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .descr = "OLSRv2 Constant Metric plugin",
+  .author = "Henning Rogge",
+
+  .cfg_section = &_constant_section,
+
+  .init = _init,
+  .cleanup = _cleanup,
+};
+DECLARE_OONF_PLUGIN(olsrv2_constant_metric_subsystem);
+
+/* timer for handling new NHDP neighbors */
+static struct oonf_timer_class _setup_timer_info = {
+  .name = "Delayed update of constant NHDP neighbor linkcosts",
+  .callback = _cb_set_linkcost,
+  .periodic = false,
+};
+
+static struct oonf_timer_instance _setup_timer = {
+  .class = &_setup_timer_info,
+};
+
+/* nhdp metric handler */
+static struct nhdp_domain_metric _constant_metric_handler = {
+  .name = OONF_CONSTANT_METRIC_SUBSYSTEM,
+};
+
+/* NHDP link listeners */
+static struct oonf_class_extension _link_extenstion = {
+  .ext_name = "constant linkmetric",
+  .class_name = NHDP_CLASS_LINK,
+
+  .cb_add = _cb_link_added,
+};
+
+/* storage for settings */
+static struct oonf_class _linkcost_class = {
+  .name = "Constant linkcost storage",
+  .size = sizeof(struct _linkcost),
+};
+
+struct avl_tree _linkcost_tree;
+
+/**
+ * Initialize plugin
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_init(void) {
+  if (nhdp_domain_metric_add(&_constant_metric_handler)) {
+    return -1;
+  }
+
+  if (oonf_class_extension_add(&_link_extenstion)) {
+    nhdp_domain_metric_remove(&_constant_metric_handler);
+    return -1;
+  }
+
+  oonf_timer_add(&_setup_timer_info);
+  oonf_class_add(&_linkcost_class);
+  avl_init(&_linkcost_tree, _avlcmp_linkcost, false);
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+  struct _linkcost *lk, *lk_it;
+
+  avl_for_each_element_safe(&_linkcost_tree, lk, _node, lk_it) {
+    avl_remove(&_linkcost_tree, &lk->_node);
+    oonf_class_free(&_linkcost_class, lk);
+  }
+
+  oonf_timer_stop(&_setup_timer);
+  oonf_timer_remove(&_setup_timer_info);
+
+  oonf_class_remove(&_linkcost_class);
+
+  oonf_class_extension_remove(&_link_extenstion);
+  nhdp_domain_metric_remove(&_constant_metric_handler);
+}
+
+/**
+ * Callback triggered when a new nhdp link is added
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_added(void *ptr __attribute__((unused))) {
+  oonf_timer_set(&_setup_timer, 1);
+}
+
+static struct _linkcost *
+_get_linkcost(const char *ifname, struct netaddr *originator) {
+  struct _linkcost key;
+  struct _linkcost *entry;
+
+  strscpy(key.if_name, ifname, IF_NAMESIZE);
+  memcpy(&key.neighbor, originator, sizeof(struct netaddr));
+
+  return avl_find_element(&_linkcost_tree, &key, entry, _node);
+}
+
+/**
+ * Timer callback to sample new ETT values into bucket
+ * @param ptr nhdp link
+ */
+static void
+_cb_set_linkcost(void *ptr __attribute__((unused))) {
+  struct nhdp_link *lnk;
+  struct _linkcost *entry;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  OONF_DEBUG(LOG_CONSTANT_METRIC, "Start setting constant linkcosts");
+  if (_constant_metric_handler.domain == NULL) {
+    return;
+  }
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    const char *ifname;
+
+    ifname = nhdp_interface_get_name(lnk->local_if);
+    OONF_DEBUG(LOG_CONSTANT_METRIC, "Look for constant metric if=%s originator=%s",
+        ifname, netaddr_to_string(&nbuf, &lnk->neigh->originator));
+
+    if (netaddr_get_address_family(&lnk->neigh->originator) == AF_UNSPEC) {
+      continue;
+    }
+
+    entry = _get_linkcost(ifname, &lnk->neigh->originator);
+    if (entry == NULL && nhdp_db_link_is_dualstack(lnk)) {
+      entry = _get_linkcost(ifname, &lnk->dualstack_partner->neigh->originator);
+    }
+    if (entry == NULL) {
+      entry = _get_linkcost(OONF_INTERFACE_WILDCARD, &lnk->neigh->originator);
+    }
+    if (entry == NULL && nhdp_db_link_is_dualstack(lnk)) {
+      entry = _get_linkcost(OONF_INTERFACE_WILDCARD,
+          &lnk->dualstack_partner->neigh->originator);
+    }
+
+    if (entry) {
+      OONF_DEBUG(LOG_CONSTANT_METRIC, "Found metric value %u", entry->cost);
+      nhdp_domain_set_incoming_metric(
+          _constant_metric_handler.domain, lnk, entry->cost);
+      continue;
+    }
+    else {
+      nhdp_domain_set_incoming_metric(
+          _constant_metric_handler.domain, lnk, RFC7181_METRIC_INFINITE);
+    }
+  }
+
+  /* update neighbor metrics */
+  nhdp_domain_neighborhood_changed();
+}
+
+static int
+_avlcmp_linkcost(const void *ptr1, const void *ptr2) {
+  const struct _linkcost *lk1, *lk2;
+  int result;
+
+  lk1 = ptr1;
+  lk2 = ptr2;
+
+  result = avl_comp_strcasecmp(&lk1->if_name, &lk2->if_name);
+  if (result == 0) {
+    result = avl_comp_netaddr(&lk1->neighbor, &lk2->neighbor);
+  }
+  return result;
+}
+
+static int
+_cb_validate_link(const struct cfg_schema_entry *entry,
+      const char *section_name, const char *value, struct autobuf *out) {
+  struct isonumber_str sbuf;
+  struct netaddr_str nbuf;
+  const char *ptr;
+  int8_t af[] = { AF_INET, AF_INET6 };
+
+  /* test if first word is a human readable number */
+  ptr = str_cpynextword(nbuf.buf, value, sizeof(nbuf));
+  if (cfg_validate_netaddr(out, section_name, entry->key.entry, nbuf.buf,
+      false, af, ARRAYSIZE(af))) {
+    return -1;
+  }
+
+  ptr = str_cpynextword(sbuf.buf, ptr, sizeof(sbuf));
+  if (cfg_validate_int(out, section_name, entry->key.entry, sbuf.buf,
+      RFC7181_METRIC_MIN, RFC7181_METRIC_MAX, 4, 0, false)) {
+    return -1;
+  }
+
+  if (ptr) {
+    cfg_append_printable_line(out, "Value '%s' for entry '%s'"
+        " in section %s should have only an address and a link cost",
+        value, entry->key.entry, section_name);
+    return -1;
+  }
+  return 0;
+}
+
+/**
+ * Callback triggered when configuration changes
+ */
+static void
+_cb_cfg_changed(void) {
+  struct _linkcost *lk, *lk_it;
+  struct netaddr_str nbuf;
+  const char *ptr, *cost_ptr;
+  const struct const_strarray *array;
+  int64_t cost;
+
+  /* remove old entries for this interface */
+  avl_for_each_element_safe(&_linkcost_tree, lk, _node, lk_it) {
+    if (strcasecmp(lk->if_name, _constant_section.section_name) == 0) {
+      avl_remove(&_linkcost_tree, &lk->_node);
+      oonf_class_free(&_linkcost_class, lk);
+    }
+  }
+
+  array = cfg_schema_tovalue(_constant_section.post, &_constant_entries[0]);
+  if (!array) {
+    OONF_DEBUG(LOG_CONSTANT_METRIC, "1");
+    return;
+  }
+
+  strarray_for_each_element(array, ptr) {
+    OONF_DEBUG(LOG_CONSTANT_METRIC, "3: %s", ptr);
+    lk = oonf_class_malloc(&_linkcost_class);
+    if (lk) {
+      cost_ptr = str_cpynextword(nbuf.buf, ptr, sizeof(nbuf));
+
+      strscpy(lk->if_name, _constant_section.section_name, IF_NAMESIZE);
+      if (netaddr_from_string(&lk->neighbor, nbuf.buf)) {
+        oonf_class_free(&_linkcost_class, lk);
+        OONF_DEBUG(LOG_CONSTANT_METRIC, "2");
+        continue;
+      }
+      if (isonumber_to_s64(&cost, cost_ptr, 0, false)) {
+        oonf_class_free(&_linkcost_class, lk);
+        OONF_DEBUG(LOG_CONSTANT_METRIC, "3");
+        continue;
+      }
+
+      lk->cost = cost;
+
+      lk->_node.key = lk;
+      avl_insert(&_linkcost_tree, &lk->_node);
+
+      OONF_DEBUG(LOG_CONSTANT_METRIC, "Add entry (%s)", ptr);
+    }
+    OONF_DEBUG(LOG_CONSTANT_METRIC, "4");
+  }
+
+  /* delay updating linkcosts */
+  oonf_timer_set(&_setup_timer, 1);
+}
diff --git a/src-plugins/nhdp/constant_metric/constant_metric.h b/src-plugins/nhdp/constant_metric/constant_metric.h
new file mode 100644 (file)
index 0000000..5865c0f
--- /dev/null
@@ -0,0 +1,54 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef CONSTANT_METRIC_H_
+#define CONSTANT_METRIC_H_
+
+#include "common/common_types.h"
+#include "core/oonf_subsystem.h"
+
+/* definitions and constants */
+#define OONF_CONSTANT_METRIC_SUBSYSTEM "constant_metric"
+
+#define LOG_CONSTANT_METRIC olsrv2_constant_metric_subsystem.logging
+EXPORT extern struct oonf_subsystem olsrv2_constant_metric_subsystem;
+
+#endif /* CONSTANT_METRIC_H_ */
diff --git a/src-plugins/nhdp/ff_dat_metric/CMakeLists.txt b/src-plugins/nhdp/ff_dat_metric/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cf72571
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (source ff_dat_metric.c)
+
+# use generic plugin maker
+oonf_create_app_plugin("ff_dat_metric" "${source}" "")
diff --git a/src-plugins/nhdp/ff_dat_metric/README_FF_DAT_METRIC b/src-plugins/nhdp/ff_dat_metric/README_FF_DAT_METRIC
new file mode 100644 (file)
index 0000000..a8c428a
--- /dev/null
@@ -0,0 +1,40 @@
+   PLUGIN USAGE
+==================
+ff_dat_plugin plugin by Henning Rogge
+
+This plugin calculates a nhdp link metric based on the approved
+Freifunk ETX metric and the outgoing linkspeed. Compared
+to the original ff_ett metric is just use the packet loss
+calculated for the incoming traffic and not the product of
+the loss-rate in both directions.
+
+The linkspeed can be either queried directly from the
+nl80211 plugin or can be set with the "linkspeed" option
+in the interface section of the configuration.
+
+The plugin assumes that the default (and minimal) linkspeed
+is 1 MBit/s. If the link is faster than this, the total cost
+is calculated by the ETX linkcost, divided by the linkspeed
+in MBit/s (up to a linkspeed of 256 MBit/s).
+
+
+
+   PLUGIN CONFIGURATION
+==========================
+
+[ff_dat_metric]
+       interval      1.0
+       window        64
+       start_window  4
+       ett           true
+
+"interval" defines the time in seconds after which the ETT-metric is
+recalculated. "window" is the number of memory slots (each "interval"
+seconds long) that are used to smooth the ETX value.
+
+"start_window" is the number of memory slots that are used at startup.
+The number of slots is increased by 1 every interval so that a link can
+quickly get up to a reasonable ETX value.
+
+"ett" allows to switch off the linkspeed part of the metric calculation,
+downgrading the metric to a directional ETT
\ No newline at end of file
diff --git a/src-plugins/nhdp/ff_dat_metric/ff_dat_metric.c b/src-plugins/nhdp/ff_dat_metric/ff_dat_metric.c
new file mode 100644 (file)
index 0000000..c15d01d
--- /dev/null
@@ -0,0 +1,810 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "common/common_types.h"
+#include "common/isonumber.h"
+#include "common/autobuf.h"
+#include "rfc5444/rfc5444_iana.h"
+#include "rfc5444/rfc5444.h"
+#include "rfc5444/rfc5444_reader.h"
+
+#include "core/oonf_cfg.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_layer2.h"
+#include "subsystems/oonf_rfc5444.h"
+#include "subsystems/oonf_timer.h"
+
+#include "nhdp/nhdp.h"
+#include "nhdp/nhdp_domain.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "ff_dat_metric/ff_dat_metric.h"
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+
+static void _cb_enable_metric(void);
+static void _cb_disable_metric(void);
+
+static void _cb_link_added(void *);
+static void _cb_link_changed(void *);
+static void _cb_link_removed(void *);
+
+static void _cb_dat_sampling(void *);
+static void _cb_hello_lost(void *);
+
+static enum rfc5444_result _cb_process_packet(
+      struct rfc5444_reader_tlvblock_context *context);
+
+static const char *_to_string(
+    struct nhdp_metric_str *buf, uint32_t metric);
+static const char *_int_to_string(struct nhdp_metric_str *,
+    struct nhdp_domain *, struct nhdp_link *);
+
+static int _cb_cfg_validate(const char *section_name,
+    struct cfg_named_section *, struct autobuf *);
+static void _cb_cfg_changed(void);
+
+/* plugin declaration */
+static struct cfg_schema_entry _datff_entries[] = {
+  CFG_MAP_CLOCK_MIN(ff_dat_config, interval, "interval", "1.0",
+      "Time interval between recalculations of metric", 100),
+  CFG_MAP_INT32_MINMAX(ff_dat_config, window, "window", "64",
+      "Number of intervals to calculate average metric", 0, false, 2, 65535),
+  CFG_MAP_BOOL(ff_dat_config, ett, "ett", "true",
+      "Activates the handling of linkspeed within the metric, set to false to"
+      " downgrade to ETX metric"),
+
+#ifdef COLLECT_RAW_DATA
+  CFG_MAP_STRING(ff_dat_config, rawdata_file, "raw_filename", "/tmp/olsrv2_dat_metric.txt",
+      "File to write recorded data into"),
+  CFG_MAP_BOOL(ff_dat_config, rawdata_start, "raw_start", "false",
+      "Set to true to activate rawdata measurement"),
+  CFG_MAP_CLOCK(ff_dat_config, rawdata_maxtime, "raw_maxtime", "3600000",
+      "Time until measurement stops"),
+  CFG_MAP_INT32_MINMAX(ff_dat_config, rawdata_maxpackets, "raw_maxpackets", "20000",
+      "Maximum number of packets to record", 0, false, 1, INT32_MAX),
+#endif
+};
+
+/* Subsystem definition */
+static struct cfg_schema_section _datff_section = {
+  .type = OONF_FF_DAT_METRIC_SUBSYSTEM,
+  .cb_validate = _cb_cfg_validate,
+  .cb_delta_handler = _cb_cfg_changed,
+  .entries = _datff_entries,
+  .entry_count = ARRAYSIZE(_datff_entries),
+};
+
+static struct ff_dat_config _datff_config;
+
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_LAYER2_SUBSYSTEM,
+  OONF_RFC5444_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+struct oonf_subsystem olsrv2_ffdat_subsystem = {
+  .name = OONF_FF_DAT_METRIC_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .descr = "OLSRv2 Funkfeuer Directional Airtime Metric plugin",
+  .author = "Henning Rogge",
+
+  .cfg_section = &_datff_section,
+
+  .init = _init,
+  .cleanup = _cleanup,
+};
+DECLARE_OONF_PLUGIN(olsrv2_ffdat_subsystem);
+
+/* RFC5444 packet listener */
+static struct oonf_rfc5444_protocol *_protocol;
+
+static struct rfc5444_reader_tlvblock_consumer _packet_consumer = {
+  .order = RFC5444_LQ_PARSER_PRIORITY,
+  .default_msg_consumer = true,
+  .start_callback = _cb_process_packet,
+};
+
+/* storage extension and listeners */
+static struct oonf_class_extension _link_extenstion = {
+  .ext_name = "datff linkmetric",
+  .class_name = NHDP_CLASS_LINK,
+  .size = sizeof(struct link_datff_data),
+
+  .cb_add = _cb_link_added,
+  .cb_change = _cb_link_changed,
+  .cb_remove = _cb_link_removed,
+};
+
+/* timer for sampling in RFC5444 packets */
+static struct oonf_timer_class _sampling_timer_info = {
+  .name = "Sampling timer for DATFF-metric",
+  .callback = _cb_dat_sampling,
+  .periodic = true,
+};
+
+static struct oonf_timer_instance _sampling_timer = {
+  .class = &_sampling_timer_info,
+};
+
+/* timer class to measure interval between Hellos */
+static struct oonf_timer_class _hello_lost_info = {
+  .name = "Hello lost timer for DATFF-metric",
+  .callback = _cb_hello_lost,
+};
+
+/* nhdp metric handler */
+static struct nhdp_domain_metric _datff_handler = {
+  .name = OONF_FF_DAT_METRIC_SUBSYSTEM,
+
+  .metric_minimum = DATFF_LINKCOST_MINIMUM,
+  .metric_maximum = DATFF_LINKCOST_MAXIMUM,
+
+  .incoming_link_start = DATFF_LINKCOST_START,
+
+  .to_string = _to_string,
+  .internal_to_string = _int_to_string,
+
+  .enable = _cb_enable_metric,
+  .disable = _cb_disable_metric,
+};
+
+/* Temporary buffer to sort incoming link speed for median calculation */
+static int *_rx_sort_array = NULL;
+
+/* rawdata collection */
+#ifdef COLLECT_RAW_DATA
+static struct autobuf _rawdata_buf;
+static int _rawdata_fd = -1;
+static uint64_t _rawdata_end = 0;
+static int _rawdata_count = 0;
+#endif
+
+/**
+ * Initialize plugin
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_init(void) {
+  if (nhdp_domain_metric_add(&_datff_handler)) {
+    return -1;
+  }
+
+  oonf_timer_add(&_sampling_timer_info);
+  oonf_timer_add(&_hello_lost_info);
+
+  _protocol = oonf_rfc5444_add_protocol(RFC5444_PROTOCOL, true);
+
+  oonf_rfc5444_add_protocol_pktseqno(_protocol);
+#ifdef COLLECT_RAW_DATA
+  abuf_init(&_rawdata_buf);
+#endif
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+#ifdef COLLECT_RAW_DATA
+  if (_rawdata_fd != -1) {
+    fsync(_rawdata_fd);
+    close(_rawdata_fd);
+  }
+  abuf_free(&_rawdata_buf);
+  free(_datff_config.rawdata_file);
+#endif
+  /* free sorting array */
+  free (_rx_sort_array);
+
+  /* remove metric from core */
+  nhdp_domain_metric_remove(&_datff_handler);
+
+  oonf_rfc5444_remove_protocol_pktseqno(_protocol);
+  oonf_rfc5444_remove_protocol(_protocol);
+
+  oonf_class_extension_remove(&_link_extenstion);
+
+  oonf_timer_stop(&_sampling_timer);
+
+  oonf_timer_remove(&_sampling_timer_info);
+  oonf_timer_remove(&_hello_lost_info);
+}
+
+static void
+_cb_enable_metric(void) {
+  struct nhdp_link *lnk;
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    _cb_link_added(lnk);
+  }
+
+  rfc5444_reader_add_packet_consumer(&_protocol->reader, &_packet_consumer, NULL, 0);
+  oonf_timer_set(&_sampling_timer, _datff_config.interval);
+}
+
+static void
+_cb_disable_metric(void) {
+  struct nhdp_link *lnk;
+
+  oonf_timer_stop(&_sampling_timer);
+  rfc5444_reader_remove_packet_consumer(&_protocol->reader, &_packet_consumer);
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    _cb_link_removed(lnk);
+  }
+}
+
+/**
+ * Callback triggered when a new nhdp link is added
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_added(void *ptr) {
+  struct link_datff_data *data;
+  struct nhdp_link *lnk;
+  int i;
+
+  lnk = ptr;
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  memset(data, 0, sizeof(*data));
+  data->activePtr = -1;
+  for (i = 0; i<_datff_config.window; i++) {
+    data->buckets[i].total = 1;
+    data->buckets[i].scaled_speed = 0;
+  }
+
+  /* start 'hello lost' timer for link */
+  data->hello_lost_timer.class = &_hello_lost_info;
+  data->hello_lost_timer.cb_context = ptr;
+}
+
+/**
+ * Callback triggered when a new nhdp link is changed
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_changed(void *ptr) {
+  struct link_datff_data *data;
+  struct nhdp_link *lnk;
+
+  lnk = ptr;
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  if (lnk->itime_value > 0) {
+    data->hello_interval = lnk->itime_value;
+  }
+  else {
+    data->hello_interval = lnk->vtime_value;
+  }
+
+  oonf_timer_set(&data->hello_lost_timer, (data->hello_interval * 3) / 2);
+
+  data->missed_hellos = 0;
+}
+
+/**
+ * Callback triggered when a nhdp link is removed from the database
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_removed(void *ptr) {
+  struct link_datff_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, ptr);
+
+  oonf_timer_stop(&data->hello_lost_timer);
+}
+
+static int
+_int_comparator(const void *p1, const void *p2) {
+  const int *i1 = (int *)p1;
+  const int *i2 = (int *)p2;
+
+  if (*i1 > *i2) {
+    return 1;
+  }
+  else if (*i1 < *i2) {
+    return -1;
+  }
+  return 0;
+}
+
+static int
+_get_median_rx_linkspeed(struct link_datff_data *ldata) {
+  int zero_count;
+  int window;
+  int i;
+
+  zero_count = 0;
+  for (i=0; i<_datff_config.window; i++) {
+    _rx_sort_array[i] = ldata->buckets[i].scaled_speed;
+    if (_rx_sort_array[i] == 0) {
+      zero_count++;
+    }
+  }
+
+  window = _datff_config.window - zero_count;
+  if (window == 0) {
+    return 1;
+  }
+
+  qsort(_rx_sort_array, _datff_config.window, sizeof(int), _int_comparator);
+
+  return _rx_sort_array[zero_count + window/2];
+}
+
+/**
+ * Retrieves the speed of a nhdp link, scaled to the minimum link speed
+ * of this metric.
+ * @param lnk nhdp link
+ * @return scaled link speed, 1 if could not be retrieved.
+ */
+static int
+_get_scaled_rx_linkspeed(struct nhdp_link *lnk) {
+  // const struct oonf_linkconfig_data *linkdata;
+  struct oonf_interface_data *ifdata;
+  const struct oonf_layer2_data *l2data;
+  int rate;
+
+  if (!_datff_config.ett) {
+    /* ETT feature is switched off */
+    return 1;
+  }
+
+  /* get local interface data  */
+  ifdata = oonf_interface_get_data(nhdp_interface_get_name(lnk->local_if), NULL);
+  if (!ifdata) {
+    return 1;
+  }
+
+  l2data = oonf_layer2_neigh_query(
+      ifdata->name, &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_BITRATE);
+  if (!l2data) {
+    return 1;
+  }
+
+  /* round up */
+  rate = (oonf_layer2_get_value(l2data) + DATFF_LINKSPEED_MINIMUM - 1) / DATFF_LINKSPEED_MINIMUM;
+  if (rate < 1) {
+    return 1;
+  }
+  if (rate > DATFF_LINKSPEED_RANGE) {
+    return DATFF_LINKSPEED_RANGE;
+  }
+  return rate;
+}
+
+/**
+ * Timer callback to sample new metric values into bucket
+ * @param ptr nhdp link
+ */
+static void
+_cb_dat_sampling(void *ptr __attribute__((unused))) {
+  struct rfc7181_metric_field encoded_metric;
+  struct link_datff_data *ldata;
+  struct nhdp_link *lnk;
+  uint32_t total, received, loss_cost_multiplier;
+  uint64_t metric;
+  uint32_t metric_value;
+  int rx_bitrate;
+  int i;
+  bool change_happened;
+
+#ifdef OONF_LOG_DEBUG_INFO
+  struct nhdp_laddr *laddr;
+  struct netaddr_str nbuf;
+#endif
+
+  OONF_DEBUG(LOG_FF_DAT, "Calculate Metric from sampled data");
+
+  change_happened = false;
+  if (!_datff_handler.domain) {
+    /* metric not used */
+    return;
+  }
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+    if (ldata->activePtr == -1) {
+      /* still no data for this link */
+      continue;
+    }
+
+    /* initialize counter */
+    total = 0;
+    received = 0;
+    loss_cost_multiplier = 1;
+
+    /* calculate metric */
+    for (i=0; i<_datff_config.window; i++) {
+      received += ldata->buckets[i].received;
+      total += ldata->buckets[i].total;
+    }
+
+    if (ldata->missed_hellos > 0) {
+      int32_t interval;
+
+      interval = ldata->missed_hellos * ldata->hello_interval / 1000;
+      if (interval > _datff_config.window) {
+        received = 0;
+      }
+      else {
+        received = (received * (_datff_config.window - interval)) / _datff_config.window;
+      }
+    }
+
+    if (total == 0 || received == 0) {
+      nhdp_domain_set_incoming_metric(_datff_handler.domain, lnk, RFC7181_METRIC_MAX);
+      continue;
+    }
+
+    /* update link speed */
+    ldata->buckets[ldata->activePtr].scaled_speed = _get_scaled_rx_linkspeed(lnk);
+#ifdef COLLECT_RAW_DATA
+    if (_rawdata_fd != -1) {
+      if (0 > write(_rawdata_fd, abuf_getptr(&_rawdata_buf), abuf_getlen(&_rawdata_buf))) {
+        close (_rawdata_fd);
+        _rawdata_fd = -1;
+      }
+      else {
+        fsync(_rawdata_fd);
+        abuf_clear(&_rawdata_buf);
+      }
+    }
+#endif
+
+    OONF_DEBUG(LOG_FF_DAT, "Query incoming linkspeed for link %s: %"PRIu64,
+        netaddr_to_string(&nbuf, &lnk->if_addr),
+        (uint64_t)(ldata->buckets[ldata->activePtr].scaled_speed) * DATFF_LINKSPEED_MINIMUM);
+
+    /* get median scaled link speed and apply it to metric */
+    rx_bitrate = _get_median_rx_linkspeed(ldata);
+    if (rx_bitrate > DATFF_LINKSPEED_RANGE) {
+      metric = 1;
+    }
+    else {
+      metric = DATFF_LINKSPEED_RANGE / rx_bitrate;
+    }
+
+    /* calculate frame loss, use discrete values */
+    if (received < total) {
+      loss_cost_multiplier = DATFF_FRAME_SUCCESS_RANGE - (DATFF_FRAME_SUCCESS_RANGE * received) / total;
+      metric *= loss_cost_multiplier;
+    }
+
+    /* convert into something that can be transmitted over the network */
+    if (metric > RFC7181_METRIC_MAX) {
+      /* give the metric an upper bound */
+      metric_value = RFC7181_METRIC_MAX;
+    }
+    else if (metric < RFC7181_METRIC_MIN) {
+      metric_value = RFC7181_METRIC_MIN;
+    }
+    else if(!rfc7181_metric_encode(&encoded_metric, metric)) {
+      metric_value = rfc7181_metric_decode(&encoded_metric);
+    }
+    else {
+      /* metric encoding failed */
+      OONF_DEBUG(LOG_FF_DAT, "Metric encoding failed for %"PRIu64, metric);
+      metric_value = RFC7181_METRIC_MAX;
+    }
+
+    /* set metric for incoming link */
+    change_happened |= nhdp_domain_set_incoming_metric(_datff_handler.domain, lnk, metric_value);
+
+    OONF_DEBUG(LOG_FF_DAT, "New sampling rate for link %s (%s):"
+        " %d/%d (%d) = %u (speed=%"PRIu64 ")\n",
+        netaddr_to_string(&nbuf, &avl_first_element(&lnk->_addresses, laddr, _link_node)->link_addr),
+        nhdp_interface_get_name(lnk->local_if),
+        received, total, loss_cost_multiplier,
+        metric_value, (uint64_t)(rx_bitrate) * DATFF_LINKSPEED_MINIMUM);
+
+    /* update rolling buffer */
+    ldata->activePtr++;
+    if (ldata->activePtr >= _datff_config.window) {
+      ldata->activePtr = 0;
+    }
+    ldata->buckets[ldata->activePtr].received = 0;
+    ldata->buckets[ldata->activePtr].total = 0;
+  }
+
+  /* update neighbor metrics */
+  if (change_happened) {
+    nhdp_domain_neighborhood_changed();
+  }
+}
+
+/**
+ * Callback triggered when the next hellos should have been received
+ * @param ptr nhdp link
+ */
+static void
+_cb_hello_lost(void *ptr) {
+  struct link_datff_data *ldata;
+  struct nhdp_link *lnk;
+
+  lnk = ptr;
+  ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  if (ldata->activePtr != -1) {
+    ldata->missed_hellos++;
+
+    oonf_timer_set(&ldata->hello_lost_timer, ldata->hello_interval);
+
+    OONF_DEBUG(LOG_FF_DAT, "Missed Hello: %d", ldata->missed_hellos);
+  }
+}
+
+/**
+ * Callback to process all in RFC5444 packets for metric calculation. The
+ * Callback ignores all unicast packets.
+ * @param consumer
+ * @param context
+ * @return
+ */
+static enum rfc5444_result
+_cb_process_packet(struct rfc5444_reader_tlvblock_context *context) {
+  struct link_datff_data *ldata;
+  struct nhdp_interface *interf;
+  struct nhdp_laddr *laddr;
+  struct nhdp_link *lnk;
+  int total;
+
+  if (!_protocol->input_is_multicast) {
+    /* silently ignore unicasts */
+    return RFC5444_OKAY;
+  }
+
+  if (!context->has_pktseqno) {
+    struct netaddr_str buf;
+
+    OONF_WARN(LOG_FF_DAT, "Neighbor %s does not send packet sequence numbers, cannot collect datff data!",
+        netaddr_socket_to_string(&buf, _protocol->input_socket));
+    return RFC5444_OKAY;
+  }
+
+  /* get interface and link */
+  interf = nhdp_interface_get(_protocol->input_interface->name);
+  if (interf == NULL) {
+    /* silently ignore unknown interface */
+    return RFC5444_OKAY;
+  }
+
+  laddr = nhdp_interface_get_link_addr(interf, _protocol->input_address);
+  if (laddr == NULL) {
+    /* silently ignore unknown link*/
+    return RFC5444_OKAY;
+  }
+
+#ifdef COLLECT_RAW_DATA
+  if (_rawdata_fd != -1)
+  {
+    uint64_t now;
+
+    now = oonf_clock_getNow();
+    _rawdata_count++;
+
+    if (now > _rawdata_end || _rawdata_count > _datff_config.rawdata_maxpackets) {
+      if (0 <= write(_rawdata_fd, abuf_getptr(&_rawdata_buf), abuf_getlen(&_rawdata_buf))) {
+        fsync(_rawdata_fd);
+      }
+      close(_rawdata_fd);
+      _rawdata_fd = -1;
+    }
+    else {
+      struct isonumber_str timebuf;
+      struct netaddr_str neighbuf;
+
+      abuf_appendf(&_rawdata_buf, "%s %s %u %d\n",
+          oonf_clock_toIntervalString(&timebuf, now),
+          netaddr_to_string(&neighbuf, &laddr->link_addr),
+          context->pkt_seqno,
+          _get_scaled_rx_linkspeed(laddr->link));
+    }
+  }
+#endif
+
+  /* get link and its dat data */
+  lnk = laddr->link;
+  ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  if (ldata->activePtr == -1) {
+    ldata->activePtr = 0;
+    ldata->buckets[0].received = 1;
+    ldata->buckets[0].total = 1;
+    ldata->last_seq_nr = context->pkt_seqno;
+
+    return RFC5444_OKAY;
+  }
+
+  total = (int)(context->pkt_seqno) - (int)(ldata->last_seq_nr);
+  if (total < 0) {
+    total += 65536;
+  }
+
+  ldata->buckets[ldata->activePtr].received++;
+  ldata->buckets[ldata->activePtr].total += total;
+  ldata->last_seq_nr = context->pkt_seqno;
+
+  return RFC5444_OKAY;
+}
+
+/**
+ * Convert DATFF metric into string representation
+ * @param buf pointer to output buffer
+ * @param metric metric value
+ * @return pointer to output string
+ */
+static const char *
+_to_string(struct nhdp_metric_str *buf, uint32_t metric) {
+  if (metric < DATFF_LINKCOST_MINIMUM) {
+    strscpy(buf->buf, "unknown", sizeof (*buf));
+  }
+  else if (metric > DATFF_LINKCOST_MAXIMUM) {
+    strscpy(buf->buf, "infinite", sizeof(*buf));
+  }
+  else {
+    isonumber_from_u64((struct isonumber_str *)buf,
+        (uint32_t)(DATFF_LINKSPEED_MINIMUM) * (uint32_t)(DATFF_LINKSPEED_RANGE) / metric,
+        "bit/s", 0, true, false);
+  }
+  return buf->buf;
+}
+
+static const char *
+_int_to_string(struct nhdp_metric_str *buf,
+    struct nhdp_domain *domain __attribute__((unused)),
+    struct nhdp_link *lnk) {
+  struct link_datff_data *ldata;
+  int64_t received = 0, total = 0;
+  int i;
+
+  ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  for (i=0; i<_datff_config.window; i++) {
+    received += ldata->buckets[i].received;
+    total += ldata->buckets[i].total;
+  }
+
+  snprintf(buf->buf, sizeof(*buf), "%"PRId64"/%"PRId64",%d kbit/s(missed=%d,lastseq=%u)",
+      received, total, _get_median_rx_linkspeed(ldata),
+      ldata->missed_hellos, ldata->last_seq_nr);
+
+  return buf->buf;
+}
+
+/**
+ * Callback triggered when configuration changes
+ */
+static void
+_cb_cfg_changed(void) {
+  bool first;
+
+  first = _datff_config.window == 0;
+
+  if (cfg_schema_tobin(&_datff_config, _datff_section.post,
+      _datff_entries, ARRAYSIZE(_datff_entries))) {
+    OONF_WARN(LOG_FF_DAT, "Cannot convert configuration for "
+        OONF_FF_DAT_METRIC_SUBSYSTEM);
+    return;
+  }
+
+  if (first) {
+    _link_extenstion.size +=
+        sizeof(struct link_datff_bucket) * _datff_config.window;
+
+    if (oonf_class_extension_add(&_link_extenstion)) {
+      return;
+    }
+
+    _rx_sort_array = calloc(_datff_config.window, sizeof(int));
+  }
+
+  /* start/change sampling timer */
+  if (_datff_handler.domain) {
+    oonf_timer_set(&_sampling_timer, _datff_config.interval);
+  }
+
+#ifdef COLLECT_RAW_DATA
+  if (_rawdata_fd != -1) {
+    fsync(_rawdata_fd);
+    close(_rawdata_fd);
+    _rawdata_end = 0;
+    _rawdata_count = 0;
+  }
+
+  if (_datff_config.rawdata_start) {
+    _rawdata_fd = open(_datff_config.rawdata_file, O_CREAT | O_TRUNC | O_WRONLY,
+               S_IRUSR|S_IWUSR);
+    if (_rawdata_fd != -1) {
+      abuf_clear(&_rawdata_buf);
+      abuf_appendf(&_rawdata_buf, "Time: %s\n", oonf_log_get_walltime());
+      _rawdata_end = oonf_clock_get_absolute(_datff_config.rawdata_maxtime);
+    }
+  }
+#endif
+}
+
+/**
+ * Callback triggered to check validity of configuration section
+ * @param section_name name of section
+ * @param named configuration data of section
+ * @param out output buffer for error messages
+ * @return 0 if data is okay, -1 if an error happened
+ */
+static int
+_cb_cfg_validate(const char *section_name,
+    struct cfg_named_section *named, struct autobuf *out) {
+  struct ff_dat_config cfg;
+
+  /* clear temporary buffer */
+  memset(&cfg, 0, sizeof(cfg));
+
+  /* convert configuration to binary */
+  if (cfg_schema_tobin(&cfg, named,
+      _datff_entries, ARRAYSIZE(_datff_entries))) {
+    cfg_append_printable_line(out, "Could not parse hysteresis configuration in section %s",
+        section_name);
+    return -1;
+  }
+
+  if (_datff_config.window != 0 && cfg.window != _datff_config.window) {
+    cfg_append_printable_line(out, "%s: DATff window cannot be changed during runtime",
+        section_name);
+    return -1;
+  }
+  return 0;
+}
diff --git a/src-plugins/nhdp/ff_dat_metric/ff_dat_metric.h b/src-plugins/nhdp/ff_dat_metric/ff_dat_metric.h
new file mode 100644 (file)
index 0000000..b0e1ad3
--- /dev/null
@@ -0,0 +1,130 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef FF_DAT_METRIC_H_
+#define FF_DAT_METRIC_H_
+
+#include "common/common_types.h"
+#include "core/oonf_subsystem.h"
+
+#define OONF_FF_DAT_METRIC_SUBSYSTEM "ff_dat_metric"
+
+/* definitions and constants */
+enum {
+  /* frame transmission success bewteen 1/8 and 8/8 */
+  DATFF_FRAME_SUCCESS_RANGE = 1<<3,
+
+  /*
+   * linkspeed between 1 kbit/s and 2 gbit/s
+   * (linkspeed_range * frame_success_range = 1<<24)
+   */
+  DATFF_LINKSPEED_MINIMUM = 1<<10,
+  DATFF_LINKSPEED_RANGE = 1<<21,
+
+  /* basic statistics of the metric */
+  DATFF_LINKCOST_START    = RFC7181_METRIC_MAX,
+  DATFF_LINKCOST_MINIMUM  = RFC7181_METRIC_MIN,
+  DATFF_LINKCOST_MAXIMUM  = RFC7181_METRIC_MAX,
+};
+
+/* Configuration settings of DATFF Metric */
+struct ff_dat_config {
+  /* Interval between two updates of the metric */
+  uint64_t interval;
+
+  /* length of history in 'interval sized' memory cells */
+  int32_t window;
+
+  /* true if metric should include link speed */
+  bool ett;
+
+#ifdef COLLECT_RAW_DATA
+  /* filename to store raw data into */
+  char *rawdata_file;
+
+  /* true if metric should collect raw data */
+  bool rawdata_start;
+
+  /* time in milliseconds until measurement stops */
+  uint64_t rawdata_maxtime;
+
+  /* maxmimum number of measured packets until measurement stops */
+  int rawdata_maxpackets;
+#endif
+};
+
+/* a single history memory cell */
+struct link_datff_bucket {
+  /* number of RFC5444 packets received in time interval */
+  int received;
+
+  /* sum of received and lost RFC5444 packets in time interval */
+  int total;
+
+  /* link speed scaled to "minimum speed = 1" */
+  int scaled_speed;
+};
+
+/* Additional data for a nhdp_link for metric calculation */
+struct link_datff_data {
+  /* current position in history ringbuffer */
+  int activePtr;
+
+  /* number of missed hellos based on timeouts since last received packet */
+  int missed_hellos;
+
+  /* last received packet sequence number */
+  uint16_t last_seq_nr;
+
+  /* timer for measuring lost hellos when no further packets are received */
+  struct oonf_timer_instance hello_lost_timer;
+
+  /* last known hello interval */
+  uint64_t hello_interval;
+
+  /* history ringbuffer */
+  struct link_datff_bucket buckets[0];
+};
+
+#define LOG_FF_DAT olsrv2_ffdat_subsystem.logging
+EXPORT extern struct oonf_subsystem olsrv2_ffdat_subsystem;
+
+#endif /* FF_DAT_METRIC_H_ */
diff --git a/src-plugins/nhdp/ff_ett_metric/CMakeLists.txt b/src-plugins/nhdp/ff_ett_metric/CMakeLists.txt
new file mode 100644 (file)
index 0000000..11196c3
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (source ff_ett_metric.c)
+
+# use generic plugin maker
+oonf_create_app_plugin("ff_ett_metric" "${source}" "")
diff --git a/src-plugins/nhdp/ff_ett_metric/README_FF_ETT_METRIC b/src-plugins/nhdp/ff_ett_metric/README_FF_ETT_METRIC
new file mode 100644 (file)
index 0000000..8d07847
--- /dev/null
@@ -0,0 +1,35 @@
+   PLUGIN USAGE
+==================
+ff_ett plugin by Henning Rogge
+
+This plugin calculates a nhdp link metric based on the approved
+Freifunk ETX metric and the outgoing linkspeed.
+
+The linkspeed can be either queried directly from the
+nl80211 plugin or can be set with the "linkspeed" option
+in the interface section of the configuration.
+
+The plugin assumes that the default (and minimal) linkspeed
+is 1 MBit/s. If the link is faster than this, the total cost
+is calculated by the ETX linkcost, divided by the linkspeed
+in MBit/s (up to a linkspeed of 256 MBit/s).
+
+This mechanism makes the ff_ett metric compatible with the ff_etx metric.
+
+
+
+   PLUGIN CONFIGURATION
+==========================
+
+[ff_ett]
+       interval        1.0
+       window          64
+       start_window    4
+
+"interval" defines the time in seconds after which the ETT-metric is
+recalculated. "window" is the number of memory slots (each "interval"
+seconds long) that are used to smooth the ETX value.
+
+"start_window" is the number of memory slots that are used at startup.
+The number of slots is increased by 1 every interval so that a link can
+quickly get up to a reasonable ETX value.
diff --git a/src-plugins/nhdp/ff_ett_metric/ff_ett_metric.c b/src-plugins/nhdp/ff_ett_metric/ff_ett_metric.c
new file mode 100644 (file)
index 0000000..57a88ab
--- /dev/null
@@ -0,0 +1,693 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, ETTA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "rfc5444/rfc5444_iana.h"
+#include "rfc5444/rfc5444.h"
+#include "rfc5444/rfc5444_reader.h"
+
+#include "core/oonf_cfg.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_plugins.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_layer2.h"
+#include "subsystems/oonf_rfc5444.h"
+#include "subsystems/oonf_packet_socket.h"
+#include "subsystems/oonf_timer.h"
+
+#include "nhdp/nhdp.h"
+#include "nhdp/nhdp_domain.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "ff_ett_metric/ff_ett_metric.h"
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+
+static void _cb_enable_metric(void);
+static void _cb_disable_metric(void);
+
+static void _cb_link_added(void *);
+static void _cb_link_changed(void *);
+static void _cb_link_removed(void *);
+
+static void _cb_ett_sampling(void *);
+static void _cb_hello_lost(void *);
+
+static enum rfc5444_result _cb_process_packet(
+      struct rfc5444_reader_tlvblock_context *context);
+
+static enum rfc5444_result _cb_addresstlvs(
+    struct rfc5444_reader_tlvblock_context *);
+static void _cb_addAddresses(struct rfc5444_writer *writer);
+
+static const char *_to_string(
+    struct nhdp_metric_str *buf, uint32_t metric);
+
+static int _cb_cfg_validate(const char *section_name,
+    struct cfg_named_section *, struct autobuf *);
+static void _cb_cfg_changed(void);
+
+/* plugin declaration */
+static struct cfg_schema_entry _ettff_entries[] = {
+  CFG_MAP_CLOCK_MIN(ff_ett_config, interval, "interval", "1.0",
+      "Time interval between recalculations of metric", 100),
+  CFG_MAP_INT32_MINMAX(ff_ett_config, window, "window", "64",
+      "Number of intervals to calculate average metric", 0, false, 2, 65535),
+  CFG_MAP_BOOL(ff_ett_config, ett, "ett", "true",
+      "Activates the handling of linkspeed within the metric, set to false to"
+      " downgrade to ETX metric"),
+};
+
+static struct cfg_schema_section _ettff_section = {
+  .type = OONF_PLUGIN_GET_NAME(),
+  .cb_validate = _cb_cfg_validate,
+  .cb_delta_handler = _cb_cfg_changed,
+  .entries = _ettff_entries,
+  .entry_count = ARRAYSIZE(_ettff_entries),
+};
+
+static struct ff_ett_config _ettff_config = { 0,0, true };
+
+struct oonf_subsystem olsrv2_ffett_subsystem = {
+  .name = OONF_PLUGIN_GET_NAME(),
+  .descr = "OLSRv2 Funkfeuer Directional Airtime Metric plugin",
+  .author = "Henning Rogge",
+
+  .cfg_section = &_ettff_section,
+
+  .init = _init,
+  .cleanup = _cleanup,
+};
+DECLARE_OONF_PLUGIN(olsrv2_ffett_subsystem);
+
+/* RFC5444 packet listener */
+static struct oonf_rfc5444_protocol *_protocol;
+
+static struct rfc5444_reader_tlvblock_consumer _packet_consumer = {
+  .order = RFC5444_LQ_PARSER_PRIORITY,
+  .default_msg_consumer = true,
+  .start_callback = _cb_process_packet,
+};
+
+/* storage extension and listeners */
+static struct oonf_class_extension _link_extenstion = {
+  .ext_name = "ettff linkmetric",
+  .class_name = NHDP_CLASS_LINK,
+  .size = sizeof(struct link_ettff_data),
+
+  .cb_add = _cb_link_added,
+  .cb_change = _cb_link_changed,
+  .cb_remove = _cb_link_removed,
+};
+
+/* timer for sampling in RFC5444 packets */
+static struct oonf_timer_class _sampling_timer_info = {
+  .name = "Sampling timer for ETTFF-metric",
+  .callback = _cb_ett_sampling,
+  .periodic = true,
+};
+
+static struct oonf_timer_instance _sampling_timer = {
+  .info = &_sampling_timer_info,
+};
+
+/* timer class to measure interval between Hellos */
+static struct oonf_timer_class _hello_lost_info = {
+  .name = "Hello lost timer for ETTFF-metric",
+  .callback = _cb_hello_lost,
+};
+
+/* nhdp metric handler */
+static struct nhdp_domain_metric _ettff_handler = {
+  .name = OONF_PLUGIN_GET_NAME(),
+
+  .metric_minimum = ETTFF_LINKCOST_MINIMUM,
+  .metric_maximum = ETTFF_LINKCOST_MAXIMUM,
+
+  .incoming_link_start = ETTFF_LINKCOST_START,
+
+  .to_string = _to_string,
+  .enable = _cb_enable_metric,
+  .disable = _cb_disable_metric,
+};
+
+/* LQ TLV handling */
+static struct rfc5444_writer_tlvtype _lq_transmit_tlv = {
+  .type = NHDP_ADDRTLV_LQ_CUSTOM,
+};
+
+static struct rfc5444_writer_content_provider _lq_content_provider = {
+  .msg_type = RFC5444_MSGTYPE_HELLO,
+  .addAddresses = _cb_addAddresses,
+};
+
+static struct rfc5444_reader_tlvblock_consumer_entry _lq_consumer_entries = {
+  .type = NHDP_ADDRTLV_LQ_CUSTOM, .match_type_ext = true,
+        .mandatory = true, .min_length = 2, .match_length = true
+};
+
+static struct rfc5444_reader_tlvblock_consumer _lq_consumer = {
+  .order = RFC5444_LQ_PARSER_PRIORITY,
+  .msg_id = RFC5444_MSGTYPE_HELLO,
+  .addrblock_consumer = true,
+  .block_callback = _cb_addresstlvs,
+};
+
+/**
+ * Initialize plugin
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_init(void) {
+  if (nhdp_domain_metric_add(&_ettff_handler)) {
+    return -1;
+  }
+
+  oonf_timer_add(&_sampling_timer_info);
+  oonf_timer_add(&_hello_lost_info);
+
+  _protocol = oonf_rfc5444_add_protocol(RFC5444_PROTOCOL, true);
+
+  oonf_rfc5444_add_protocol_pktseqno(_protocol);
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+  /* remove metric from core */
+  nhdp_domain_metric_remove(&_ettff_handler);
+
+  oonf_rfc5444_remove_protocol_pktseqno(_protocol);
+  oonf_rfc5444_remove_protocol(_protocol);
+
+  oonf_class_extension_remove(&_link_extenstion);
+
+  oonf_timer_stop(&_sampling_timer);
+
+  oonf_timer_remove(&_sampling_timer_info);
+  oonf_timer_remove(&_hello_lost_info);
+}
+
+static void
+_cb_enable_metric(void) {
+  struct nhdp_link *lnk;
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    _cb_link_added(lnk);
+  }
+
+  /* register packet consumer for reading packet sequence number */
+  rfc5444_reader_add_packet_consumer(&_protocol->reader, &_packet_consumer, NULL, 0);
+
+  /* register address TLV for exchanging LQ to neighbors */
+  _lq_transmit_tlv.exttype = _ettff_handler.domain->ext;
+  rfc5444_writer_register_addrtlvtype(&_protocol->writer,
+      &_lq_transmit_tlv, -1);
+
+  /* register consumer for LQ handling */
+  rfc5444_reader_add_message_consumer(&_protocol->reader, &_lq_consumer, &_lq_consumer_entries, 1);
+
+  /* start sampling timer */
+  oonf_timer_set(&_sampling_timer, _ettff_config.interval);
+}
+
+static void
+_cb_disable_metric(void) {
+  struct nhdp_link *lnk;
+
+  /* Stop timer that samples recv/loss buckets */
+  oonf_timer_stop(&_sampling_timer);
+
+  /* unregister consumer and address TLV */
+  rfc5444_reader_remove_packet_consumer(&_protocol->reader, &_packet_consumer);
+  rfc5444_reader_remove_message_consumer(&_protocol->reader, &_lq_consumer);
+  rfc5444_writer_unregister_addrtlvtype(&_protocol->writer, &_lq_transmit_tlv);
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    _cb_link_removed(lnk);
+  }
+}
+
+/**
+ * Callback triggered when a new nhdp link is added
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_added(void *ptr) {
+  struct link_ettff_data *data;
+  struct nhdp_link *lnk;
+  int i;
+
+  lnk = ptr;
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  memset(data, 0, sizeof(*data));
+  data->activePtr = -1;
+
+  for (i = 0; i<_ettff_config.window; i++) {
+    data->buckets[i].total = 1;
+  }
+
+  /* start 'hello lost' timer for link */
+  data->hello_lost_timer.info = &_hello_lost_info;
+  data->hello_lost_timer.cb_context = ptr;
+}
+
+/**
+ * Callback triggered when a new nhdp link is changed
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_changed(void *ptr) {
+  struct link_ettff_data *data;
+  struct nhdp_link *lnk;
+
+  lnk = ptr;
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  /* if we have an interval time, remember it. If not, use validity time */
+  if (lnk->itime_value > 0) {
+    data->hello_interval = lnk->itime_value;
+  }
+  else {
+    data->hello_interval = lnk->vtime_value;
+  }
+
+  /* we begin with the worst LQ for the neighbor */
+  data->neighbor_lq = 1;
+
+  /* we didn't missed any hellos */
+  data->missed_hellos = 0;
+
+  /* start timer to detect lost Hellos */
+  oonf_timer_set(&data->hello_lost_timer, (data->hello_interval * 3) / 2);
+}
+
+/**
+ * Callback triggered when a nhdp link is removed from the database
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_removed(void *ptr) {
+  struct link_ettff_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, ptr);
+
+  oonf_timer_stop(&data->hello_lost_timer);
+}
+
+static uint64_t
+_get_rx_linkspeed(struct nhdp_link *lnk) {
+  // const struct oonf_linkconfig_data *linkdata;
+  struct oonf_interface_data *ifdata;
+  const struct oonf_layer2_data *l2data;
+
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str nbuf;
+#endif
+
+  if (!_ettff_config.ett) {
+    /* ETT feature is switched off */
+    return 0;
+  }
+
+  OONF_DEBUG(LOG_FF_ETT, "Query incoming linkspeed for link %s",
+      netaddr_to_string(&nbuf, &lnk->if_addr));
+
+  /* get local interface data  */
+  ifdata = oonf_interface_get_data(nhdp_interface_get_name(lnk->local_if), NULL);
+  if (!ifdata) {
+    return 0;
+  }
+
+  l2data = oonf_layer2_neigh_query(
+      &ifdata->mac, &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_BITRATE);
+  if (l2data) {
+    return oonf_layer2_get_value(l2data);
+  }
+  return 0;
+}
+
+/**
+ * Timer callback to sample new metric values into bucket
+ * @param ptr nhdp link
+ */
+static void
+_cb_ett_sampling(void *ptr __attribute__((unused))) {
+  struct link_ettff_data *ldata;
+  struct nhdp_link *lnk;
+  uint32_t total, received;
+  uint64_t metric;
+  uint64_t rx_bitrate;
+  int i;
+
+#ifdef OONF_LOG_DEBUG_INFO
+  struct nhdp_laddr *laddr;
+  struct netaddr_str buf;
+#endif
+
+  OONF_DEBUG(LOG_FF_ETT, "Calculate Metric from sampled data");
+
+  if (!_ettff_handler.domain) {
+    /* metric not used */
+    return;
+  }
+
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+    if (ldata->activePtr == -1) {
+      /* still no data for this link */
+      continue;
+    }
+
+    /* initialize counter */
+    total = 0;
+    received = 0;
+
+    /* calculate metric */
+    for (i=0; i<_ettff_config.window; i++) {
+      received += ldata->buckets[i].received;
+      total += ldata->buckets[i].total;
+    }
+
+    /* TODO: whats about overflow if rec >= 65536 ? */
+    ldata->last_lq = 65535 * received / total;
+
+    if (ldata->missed_hellos > 0) {
+      total += (total * ldata->missed_hellos * ldata->hello_interval) /
+          (_ettff_config.interval * _ettff_config.window);
+    }
+
+    /* calculate MIN(MIN * total / received, MAX) */
+    if (received * (ETTFF_ETXCOST_MAXIMUM/ETTFF_ETXCOST_MINIMUM) < total) {
+      metric = ETTFF_ETXCOST_MAXIMUM;
+    }
+    else {
+      metric = (ETTFF_ETXCOST_MINIMUM * total) / received;
+    }
+
+    /* get link speed */
+    rx_bitrate = _get_rx_linkspeed(lnk);
+
+    /* apply linkspeed to metric */
+    if (rx_bitrate > ETTFF_LINKSPEED_MAXIMUM) {
+      metric /= (ETTFF_LINKSPEED_MAXIMUM / ETTFF_LINKSPEED_MINIMUM);
+    }
+    else if (rx_bitrate > ETTFF_LINKSPEED_MINIMUM) {
+      metric /= (rx_bitrate / ETTFF_LINKSPEED_MINIMUM);
+    }
+
+    /* convert into something that can be transmitted over the network */
+    metric = rfc7181_metric_encode(metric);
+    metric = rfc7181_metric_decode(metric);
+
+    nhdp_domain_set_incoming_metric(_ettff_handler.domain, lnk, metric);
+
+    OONF_DEBUG(LOG_FF_ETT, "New sampling rate for link %s (%s):"
+        " %d/%d = %" PRIu64 " (speed=%"PRIu64 ")\n",
+        netaddr_to_string(&buf, &avl_first_element(&lnk->_addresses, laddr, _link_node)->link_addr),
+        nhdp_interface_get_name(lnk->local_if),
+        received, total, metric, rx_bitrate);
+
+    /* upette rolling buffer */
+    ldata->activePtr++;
+    if (ldata->activePtr >= _ettff_config.window) {
+      ldata->activePtr = 0;
+    }
+    ldata->buckets[ldata->activePtr].received = 0;
+    ldata->buckets[ldata->activePtr].total = 0;
+  }
+
+  /* upette neighbor metrics */
+  nhdp_domain_neighborhood_changed();
+}
+
+/**
+ * Callback triggered when the next hellos should have been received
+ * @param ptr nhdp link
+ */
+static void
+_cb_hello_lost(void *ptr) {
+  struct link_ettff_data *ldata;
+  struct nhdp_link *lnk;
+
+  lnk = ptr;
+  ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  if (ldata->activePtr != -1) {
+    ldata->missed_hellos++;
+
+    oonf_timer_set(&ldata->hello_lost_timer, ldata->hello_interval);
+
+    OONF_DEBUG(LOG_FF_ETT, "Missed Hello: %d", ldata->missed_hellos);
+  }
+}
+
+/**
+ * Callback to process all in RFC5444 packets for metric calculation. The
+ * Callback ignores all unicast packets.
+ * @param consumer
+ * @param context
+ * @return
+ */
+static enum rfc5444_result
+_cb_process_packet(struct rfc5444_reader_tlvblock_context *context) {
+  struct link_ettff_data *ldata;
+  struct nhdp_interface *interf;
+  struct nhdp_laddr *laddr;
+  struct nhdp_link *lnk;
+  int total;
+
+  if (!_protocol->input_is_multicast) {
+    /* silently ignore unicasts */
+    return RFC5444_OKAY;
+  }
+
+  if (!context->has_pktseqno) {
+    struct netaddr_str buf;
+
+    OONF_WARN(LOG_FF_ETT, "Neighbor %s does not send packet sequence numbers, cannot collect ettff data!",
+        netaddr_socket_to_string(&buf, _protocol->input_socket));
+    return RFC5444_OKAY;
+  }
+
+  /* get interface and link */
+  interf = nhdp_interface_get(_protocol->input_interface->name);
+  if (interf == NULL) {
+    /* silently ignore unknown interface */
+    return RFC5444_OKAY;
+  }
+
+  laddr = nhdp_interface_get_link_addr(interf, _protocol->input_address);
+  if (laddr == NULL) {
+    /* silently ignore unknown link*/
+    return RFC5444_OKAY;
+  }
+
+  /* get link and its ett data */
+  lnk = laddr->link;
+  ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  if (ldata->activePtr == -1) {
+    ldata->activePtr = 0;
+    ldata->buckets[0].received = 1;
+    ldata->buckets[0].total = 1;
+    ldata->last_seq_nr = context->pkt_seqno;
+
+    return RFC5444_OKAY;
+  }
+
+  total = (int)(context->pkt_seqno) - (int)(ldata->last_seq_nr);
+  if (total < 0) {
+    total += 65536;
+  }
+
+  ldata->buckets[ldata->activePtr].received++;
+  ldata->buckets[ldata->activePtr].total += total;
+  ldata->last_seq_nr = context->pkt_seqno;
+
+  return RFC5444_OKAY;
+}
+
+static enum rfc5444_result
+_cb_addresstlvs(struct rfc5444_reader_tlvblock_context *context) {
+  struct nhdp_interface *ninterf;
+  struct link_ettff_data *ldata;
+  struct nhdp_link *lnk;
+  uint16_t nlq;
+
+  ninterf = nhdp_interface_get(_protocol->input_interface->name);
+
+  lnk = avl_find_element(&ninterf->_link_addresses, &context->addr, lnk, _if_node);
+  if (lnk) {
+    ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+    memcpy(&nlq, _lq_consumer_entries.tlv->single_value, sizeof(nlq));
+    ldata->neighbor_lq = ntohs(nlq);
+  }
+  return RFC5444_OKAY;
+}
+
+static void
+_cb_addAddresses(struct rfc5444_writer *writer) {
+  struct oonf_rfc5444_target *target;
+  struct rfc5444_writer_address *addr;
+  struct link_ettff_data *ldata;
+  struct nhdp_laddr *laddr;
+  struct nhdp_link *lnk;
+
+  uint16_t value;
+
+  /* have already be checked for message TLVs, so they cannot be NULL */
+  target = oonf_rfc5444_get_target_from_writer(writer);
+
+  /* then transmit neighbor addresses */
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    ldata = oonf_class_get_extension(&_link_extenstion, lnk);
+
+    value = htons(ldata->last_lq);
+
+    avl_for_each_element(&lnk->_addresses, laddr, _link_node) {
+      if (netaddr_get_address_family(&laddr->link_addr)
+          == netaddr_get_address_family(&target->dst)) {
+        addr = rfc5444_writer_add_address(&_protocol->writer,
+            _lq_content_provider.creator, &laddr->link_addr, false);
+
+        if (addr) {
+          rfc5444_writer_add_addrtlv(&_protocol->writer, addr,
+              &_lq_transmit_tlv, &value, sizeof(value), false);
+        }
+      }
+    }
+  }
+}
+
+
+/**
+ * Convert ETTFF metric into string representation
+ * @param buf pointer to output buffer
+ * @param metric metric value
+ * @return pointer to output string
+ */
+static const char *
+_to_string(struct nhdp_metric_str *buf, uint32_t metric) {
+  uint32_t frac;
+
+  frac = metric % ETTFF_LINKCOST_MINIMUM;
+  frac *= 1000;
+  frac /= ETTFF_LINKCOST_MINIMUM;
+  snprintf(buf->buf, sizeof(*buf), "%u.%03u",
+      metric / ETTFF_LINKCOST_MINIMUM, frac);
+
+  return buf->buf;
+}
+
+/**
+ * Callback triggered when configuration changes
+ */
+static void
+_cb_cfg_changed(void) {
+  bool first;
+
+  first = _ettff_config.window == 0;
+
+  if (cfg_schema_tobin(&_ettff_config, _ettff_section.post,
+      _ettff_entries, ARRAYSIZE(_ettff_entries))) {
+    OONF_WARN(LOG_FF_ETT, "Cannot convert configuration for %s",
+        OONF_PLUGIN_GET_NAME());
+    return;
+  }
+
+  if (first) {
+    _link_extenstion.size +=
+        sizeof(struct link_ettff_bucket) * _ettff_config.window;
+
+    if (oonf_class_extension_add(&_link_extenstion)) {
+      return;
+    }
+  }
+
+  /* start/change sampling timer */
+  if (_ettff_handler.domain) {
+    oonf_timer_set(&_sampling_timer, _ettff_config.interval);
+  }
+}
+
+/**
+ * Callback triggered to check validity of configuration section
+ * @param section_name name of section
+ * @param named configuration data of section
+ * @param out output buffer for error messages
+ * @return 0 if data is okay, -1 if an error happened
+ */
+static int
+_cb_cfg_validate(const char *section_name,
+    struct cfg_named_section *named, struct autobuf *out) {
+  struct ff_ett_config cfg;
+
+  /* clear temporary buffer */
+  memset(&cfg, 0, sizeof(cfg));
+
+  /* convert configuration to binary */
+  if (cfg_schema_tobin(&cfg, named,
+      _ettff_entries, ARRAYSIZE(_ettff_entries))) {
+    cfg_append_printable_line(out, "Could not parse hysteresis configuration in section %s",
+        section_name);
+    return -1;
+  }
+
+  if (_ettff_config.window != 0 && cfg.window != _ettff_config.window) {
+    cfg_append_printable_line(out, "%s: ETTff window cannot be changed during runtime",
+        section_name);
+    return -1;
+  }
+  return 0;
+}
similarity index 51%
rename from src-api/core/oonf_plugins.h
rename to src-plugins/nhdp/ff_ett_metric/ff_ett_metric.h
index e256d7f..325ca16 100644 (file)
  *
  */
 
-#ifndef _OONF_PLUGIN_LOADER
-#define _OONF_PLUGIN_LOADER
+#ifndef FF_ETX_H_
+#define FF_ETX_H_
 
 #include "common/common_types.h"
-#include "common/avl.h"
-#include "common/list.h"
-
 #include "core/oonf_subsystem.h"
 
-struct oonf_plugin_namebuf {
-  char name[OONF_SUBSYSTEM_NAMESIZE];
+/* definitions and constants */
+enum {
+  ETTFF_LINKSPEED_MINIMUM = 1024 * 1024,
+  ETTFF_LINKSPEED_MAXIMUM = ETTFF_LINKSPEED_MINIMUM * 256,
+
+  ETTFF_ETXCOST_MINIMUM   = RFC7181_METRIC_MIN,
+  ETTFF_ETXCOST_MAXIMUM   = RFC7181_METRIC_MAX,
+
+  ETTFF_LINKCOST_START    = RFC7181_METRIC_MAX,
+  ETTFF_LINKCOST_MINIMUM  =
+      ETTFF_ETXCOST_MINIMUM *
+      (ETTFF_LINKSPEED_MAXIMUM / ETTFF_LINKSPEED_MINIMUM),
+  ETTFF_LINKCOST_MAXIMUM  = ETTFF_ETXCOST_MAXIMUM,
+};
+
+/* Configuration settings of ETTFF Metric */
+struct ff_ett_config {
+  /* Interval between two updates of the metric */
+  uint64_t interval;
+
+  /* length of history in 'interval sized' memory cells */
+  int32_t window;
+
+  /* true if metric should include link speed */
+  bool ett;
 };
 
-#define DECLARE_OONF_PLUGIN(subsystem) _OONF_PLUGIN_DEF(PLUGIN_FULLNAME, subsystem)
+/* a single history memory cell */
+struct link_ettff_bucket {
+  /* number of RFC5444 packets received in time interval */
+  int received;
 
-#define _OONF_PLUGIN_DEF(plg_name, subsystem) _OONF_PLUGIN_DEF2(plg_name, subsystem)
-#define _OONF_PLUGIN_DEF2(plg_name, subsystem) EXPORT void hookup_plugin_ ## plg_name (void) __attribute__ ((constructor)); void hookup_plugin_ ## plg_name (void) { oonf_plugins_hook(&subsystem); }
+  /* sum of received and lost RFC5444 packets in time interval */
+  int total;
+};
 
-#define OONF_PLUGIN_GET_NAME() _OONF_PLUGIN_GET_NAME(PLUGIN_FULLNAME)
-#define _OONF_PLUGIN_GET_NAME(plg_name) STRINGIFY(plg_name)
+/* Additional data for a nhdp_link for metric calculation */
+struct link_ettff_data {
+  /* current position in history ringbuffer */
+  int activePtr;
 
-EXPORT extern struct avl_tree oonf_plugin_tree;
+  /* number of missed hellos based on timeouts since last received packet */
+  int missed_hellos;
 
-EXPORT void oonf_plugins_init(void);
-EXPORT void oonf_plugins_initiate_shutdown(void);
-EXPORT void oonf_plugins_cleanup(void);
-EXPORT void oonf_plugins_set_path(const char *path);
+  /* last received packet sequence number */
+  uint16_t last_seq_nr;
 
-EXPORT void oonf_plugins_hook(struct oonf_subsystem *subsystem);
+  /* timer for measuring lost hellos when no further packets are received */
+  struct oonf_timer_instance hello_lost_timer;
 
-EXPORT int oonf_plugins_call_init(struct oonf_subsystem *plugin);
-EXPORT void oonf_plugins_call_cleanup(struct oonf_subsystem *plugin);
+  /* last known hello interval */
+  uint64_t hello_interval;
 
-EXPORT void oonf_plugins_extract_name(
-    struct oonf_plugin_namebuf *buf, const char *libname);
+  /* last calculated LQ (multiplied by 65535) */
+  uint16_t last_lq;
 
-EXPORT struct oonf_subsystem *oonf_plugins_load(const char *);
-EXPORT void oonf_plugins_initiate_unload(struct oonf_subsystem *);
-EXPORT int oonf_plugins_unload(struct oonf_subsystem *);
+  /* last reported LQ of neighbor (multiplied by 65535) */
+  uint16_t neighbor_lq;
 
-/**
- * Query for a certain plugin name
- * @param libname name of plugin
- * @return pointer to plugin db entry, NULL if not found
- */
-static INLINE struct oonf_subsystem *
-oonf_plugins_get(const char *libname) {
-  struct oonf_subsystem *plugin;
+  /* history ringbuffer */
+  struct link_ettff_bucket buckets[0];
+};
 
-  return avl_find_element(&oonf_plugin_tree, libname, plugin, _node);
-}
+#define LOG_FF_ETT olsrv2_ffett_subsystem.logging
+EXPORT extern struct oonf_subsystem olsrv2_ffett_subsystem;
 
-#endif
+#endif /* FF_ETX_H_ */
diff --git a/src-plugins/nhdp/hysteresis_olsrv1/CMakeLists.txt b/src-plugins/nhdp/hysteresis_olsrv1/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6978d1d
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (source hysteresis_olsrv1.c)
+
+# use generic plugin maker
+oonf_create_app_plugin("hysteresis_olsrv1" "${source}" "" "")
diff --git a/src-plugins/nhdp/hysteresis_olsrv1/README_HYSTERESIS_OLSRV1 b/src-plugins/nhdp/hysteresis_olsrv1/README_HYSTERESIS_OLSRV1
new file mode 100644 (file)
index 0000000..3606d17
--- /dev/null
@@ -0,0 +1,26 @@
+   PLUGIN USAGE
+==================
+Hysteresis_olsrv1 plugin by Henning Rogge
+
+This plugin calculates a nhdp link hysteresis similar to the mechanism suggested in OLSRv1.
+
+It use an exponential averaging on incoming (and missing) HELLOs to calculate a link quality between 0 and 1 and
+two treshold values to convert the link quality into a binary value.
+
+Its mostly useded as a demonstrator of the hysteresis API of NHDP.
+
+
+   PLUGIN CONFIGURATION
+==========================
+
+[hysteresis_olsrv1]
+    accept 0.7
+    reject 0.3
+    scaling 0.1
+
+
+The "accept" value defines the treshold at which the link goes up, the "reject" value the treshold when the link goes down.
+
+"Scaling" controls the speed of the exponential aging, lower scaling values mean a slower change of the link quality.
+
+All three parameters must be values between 0 and 1.
diff --git a/src-plugins/nhdp/hysteresis_olsrv1/hysteresis_olsrv1.c b/src-plugins/nhdp/hysteresis_olsrv1/hysteresis_olsrv1.c
new file mode 100644 (file)
index 0000000..2dfad01
--- /dev/null
@@ -0,0 +1,388 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <stdio.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "rfc5444/rfc5444_iana.h"
+#include "rfc5444/rfc5444.h"
+#include "rfc5444/rfc5444_reader.h"
+#include "core/oonf_cfg.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_rfc5444.h"
+#include "subsystems/oonf_timer.h"
+
+#include "nhdp/nhdp_hysteresis.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "hysteresis_olsrv1/hysteresis_olsrv1.h"
+
+/* definitions and constants */
+#define CFG_HYSTERESIS_OONFV1_SECTION "hysteresis_olsrv1"
+
+struct _config {
+  int accept;
+  int reject;
+  int scaling;
+};
+
+struct link_hysteresis_data {
+  uint64_t interval;
+  int32_t quality;
+  bool pending, lost;
+
+  struct oonf_timer_instance interval_timer;
+};
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+
+static void _update_hysteresis(struct nhdp_link *,
+    struct link_hysteresis_data *, bool);
+
+static void _cb_link_added(void *);
+static void _cb_link_removed(void *);
+
+static void _cb_update_hysteresis(struct nhdp_link *,
+    struct rfc5444_reader_tlvblock_context *context);
+static bool _cb_is_pending(struct nhdp_link *);
+static bool _cb_is_lost(struct nhdp_link *);
+static const char *_cb_to_string(
+    struct nhdp_hysteresis_str *, struct nhdp_link *);
+
+static void _cb_timer_hello_lost(void *);
+static void _cb_cfg_changed(void);
+static int _cb_cfg_validate(const char *section_name,
+    struct cfg_named_section *, struct autobuf *);
+
+/* configuration options */
+static struct cfg_schema_entry _hysteresis_entries[] = {
+  CFG_MAP_INT32_MINMAX(_config, accept, "accept", "0.7",
+      "link quality to consider a link up", 3, false, 0, 1000),
+  CFG_MAP_INT32_MINMAX(_config, reject, "reject", "0.3",
+      "link quality to consider a link down", 3, false, 0, 1000),
+  CFG_MAP_INT32_MINMAX(_config, scaling, "scaling", "0.25",
+      "exponential aging to control speed of link hysteresis", 3, false, 1, 1000),
+};
+
+static struct cfg_schema_section _hysteresis_section = {
+  .type = CFG_HYSTERESIS_OONFV1_SECTION,
+  .cb_delta_handler = _cb_cfg_changed,
+  .cb_validate = _cb_cfg_validate,
+  .entries = _hysteresis_entries,
+  .entry_count = ARRAYSIZE(_hysteresis_entries),
+};
+
+static struct _config _hysteresis_config;
+
+/* plugin declaration */
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_RFC5444_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+  OONF_NHDP_SUBSYSTEM,
+};
+struct oonf_subsystem olsrv2_hysteresis_olsrv1_subsystem = {
+  .name = OONF_HYSTERESIS_OLSRV1_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .descr = "OONFD2 olsrv1-style hysteresis plugin",
+  .author = "Henning Rogge",
+
+  .cfg_section = &_hysteresis_section,
+
+  .init = _init,
+  .cleanup = _cleanup,
+};
+DECLARE_OONF_PLUGIN(olsrv2_hysteresis_olsrv1_subsystem);
+
+/* storage extension for nhdp_link */
+struct oonf_class_extension _link_extenstion = {
+  .ext_name = OONF_HYSTERESIS_OLSRV1_SUBSYSTEM,
+  .class_name = NHDP_CLASS_LINK,
+  .size = sizeof(struct link_hysteresis_data),
+  .cb_add = _cb_link_added,
+  .cb_remove = _cb_link_removed,
+};
+
+/* timer class to measure interval between Hellos */
+struct oonf_timer_class _hello_timer_info = {
+  .name = "Hello interval timeout for hysteresis",
+  .callback = _cb_timer_hello_lost,
+};
+
+/* hysteresis handler */
+struct nhdp_hysteresis_handler _hysteresis_handler = {
+  .name = "hysteresis_olsrv1",
+  .update_hysteresis = _cb_update_hysteresis,
+  .is_pending = _cb_is_pending,
+  .is_lost = _cb_is_lost,
+  .to_string = _cb_to_string,
+};
+
+/**
+ * Initialize plugin
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_init(void) {
+  if (oonf_class_is_extension_registered(&_link_extenstion)) {
+    struct nhdp_link *lnk;
+
+    /* add all custom extensions for link */
+    list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+      _cb_link_added(lnk);
+    }
+  }
+  else if (oonf_class_extension_add(&_link_extenstion)) {
+    return -1;
+  }
+
+  nhdp_hysteresis_set_handler(&_hysteresis_handler);
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+  struct nhdp_link *lnk;
+
+  /* remove all custom extensions for link */
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    _cb_link_removed(lnk);
+  }
+
+  nhdp_hysteresis_set_handler(NULL);
+  oonf_class_extension_remove(&_link_extenstion);
+}
+
+/**
+ * Update the quality value of a link
+ * @param lnk pointer to nhdp link
+ * @param data pointer to link hysteresis data
+ * @param lost true if hello was lost, false if hello was received
+ */
+static void
+_update_hysteresis(struct nhdp_link *lnk,
+    struct link_hysteresis_data *data, bool lost) {
+  /* calculate exponential aging */
+  data->quality = data->quality * (1000 - _hysteresis_config.scaling);
+  data->quality = (data->quality + 999) / 1000;
+  if (!lost) {
+    data->quality += _hysteresis_config.scaling;
+  }
+
+  if (!data->pending && !data->lost) {
+    if (data->quality < _hysteresis_config.reject) {
+      data->lost = true;
+      nhdp_db_link_update_status(lnk);
+    }
+  }
+  else {
+    if (data->quality > _hysteresis_config.accept) {
+      data->pending = false;
+      data->lost = false;
+      nhdp_db_link_update_status(lnk);
+    }
+  }
+}
+
+/**
+ * Callback triggered when a new nhdp link is added
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_added(void *ptr) {
+  struct link_hysteresis_data *data;
+  data = oonf_class_get_extension(&_link_extenstion, ptr);
+
+  memset(data, 0, sizeof(*data));
+  data->pending = true;
+
+  data->interval_timer.class = &_hello_timer_info;
+  data->interval_timer.cb_context = ptr;
+}
+
+/**
+ * Callback triggered when a nhdp link will be removed
+ * @param ptr nhdp link
+ */
+static void
+_cb_link_removed(void *ptr) {
+  struct link_hysteresis_data *data;
+  data = oonf_class_get_extension(&_link_extenstion, ptr);
+
+  oonf_timer_stop(&data->interval_timer);
+}
+
+/**
+ * Callback for hysteresis handler which is triggered to
+ * update the hysteresis when a HELLO is received.
+ * @param lnk nhdp link
+ * @param context RFC5444 message context
+ * @param vtime validity time
+ * @param itime interval time, 0 if not set
+ */
+static void
+_cb_update_hysteresis(struct nhdp_link *lnk,
+    struct rfc5444_reader_tlvblock_context *context __attribute__((unused))) {
+  struct link_hysteresis_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  /* update hysteresis because of received hello */
+  _update_hysteresis(lnk, data, false);
+
+  /* store interval */
+  data->interval = lnk->itime_value;
+
+  /* first timer gets a delay */
+  if (data->interval == 0) {
+    data->interval = lnk->vtime_value;
+  }
+  oonf_timer_set(&data->interval_timer, (data->interval * 3) / 2);
+}
+
+/**
+ * Callback for hysteresis handler to check if link is pending
+ * @param lnk nhdp link
+ * @return true if link is pending, false otherwise
+ */
+static bool
+_cb_is_pending(struct nhdp_link *lnk) {
+  struct link_hysteresis_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+  return data->pending;
+}
+
+/**
+ * Callback for hysteresis handler to check if link is lost
+ * @param lnk nhdp link
+ * @return true if link is lost, false otherwise
+ */
+static bool
+_cb_is_lost(struct nhdp_link *lnk) {
+  struct link_hysteresis_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+  return data->lost;
+}
+
+/**
+ * Callback for hysteresis handler to get a human readable
+ * from of the current hysteresis data.
+ * @param buf output buffer
+ * @param lnk nhdp link
+ * @return pointer to output buffer
+ */
+static const char *
+_cb_to_string(struct nhdp_hysteresis_str *buf, struct nhdp_link *lnk) {
+  struct isonumber_str fbuf;
+  struct link_hysteresis_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, lnk);
+
+  snprintf(buf->buf, sizeof(*buf), "quality=%s",
+      isonumber_from_s64(&fbuf, data->quality, "", 3, false, true));
+
+  return buf->buf;
+}
+
+/**
+ * Timer callback triggered when Hello was lost
+ * @param ptr nhdp link
+ */
+static void
+_cb_timer_hello_lost(void *ptr) {
+  struct link_hysteresis_data *data;
+
+  data = oonf_class_get_extension(&_link_extenstion, ptr);
+
+  /* update hysteresis because of lost Hello */
+  _update_hysteresis(ptr, data, true);
+
+  /* reactivate timer */
+  oonf_timer_set(&data->interval_timer, data->interval);
+}
+
+/**
+ * Callback triggered when configuration changes
+ */
+static void
+_cb_cfg_changed(void) {
+  cfg_schema_tobin(&_hysteresis_config, _hysteresis_section.post,
+      _hysteresis_entries, ARRAYSIZE(_hysteresis_entries));
+}
+
+/**
+ * Callback triggered to check validity of configuration section
+ * @param section_name name of section
+ * @param named configuration data of section
+ * @param out output buffer for error messages
+ * @return 0 if data is okay, -1 if an error happened
+ */
+static int
+_cb_cfg_validate(const char *section_name,
+    struct cfg_named_section *named, struct autobuf *out) {
+  struct _config cfg;
+  struct isonumber_str buf1, buf2;
+
+  if (cfg_schema_tobin(&cfg, named, _hysteresis_entries, ARRAYSIZE(_hysteresis_entries))) {
+    cfg_append_printable_line(out, "Could not parse hysteresis configuration in section %s",
+        section_name);
+    return -1;
+  }
+
+  if (cfg.accept <= cfg.reject) {
+    cfg_append_printable_line(out, "hysteresis accept (%s) is not smaller than reject (%s) value",
+        isonumber_from_s64(&buf1, cfg.accept, "", 3, false, true),
+        isonumber_from_s64(&buf2, cfg.reject, "", 3, false, true));
+    return -1;
+  }
+  return 0;
+}
diff --git a/src-plugins/nhdp/hysteresis_olsrv1/hysteresis_olsrv1.h b/src-plugins/nhdp/hysteresis_olsrv1/hysteresis_olsrv1.h
new file mode 100644 (file)
index 0000000..d099135
--- /dev/null
@@ -0,0 +1,53 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef HYSTERESIS_OONFV1_H_
+#define HYSTERESIS_OONFV1_H_
+
+#include "common/common_types.h"
+#include "core/oonf_subsystem.h"
+
+#define OONF_HYSTERESIS_OLSRV1_SUBSYSTEM "hysteresis_olsrv1"
+
+#define LOG_HYSTERESIS_OLSRV1 olsrv2_hysteresis_olsrv1_subsystem.logging
+EXPORT extern struct oonf_subsystem olsrv2_hysteresis_olsrv1_subsystem;
+
+#endif /* HYSTERESIS_OONFV1_H_ */
diff --git a/src-plugins/nhdp/mpr/CMakeLists.txt b/src-plugins/nhdp/mpr/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f72c003
--- /dev/null
@@ -0,0 +1,5 @@
+# set library parameters
+SET (source mpr.c neighbor-graph.c neighbor-graph-flooding.c neighbor-graph-routing.c selection-rfc7181.c)
+
+# use generic plugin maker
+oonf_create_app_plugin("mpr" "${source}" "")
diff --git a/src-plugins/nhdp/mpr/mpr.c b/src-plugins/nhdp/mpr/mpr.c
new file mode 100644 (file)
index 0000000..6a44831
--- /dev/null
@@ -0,0 +1,337 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/container_of.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_logging.h"
+#include "core/oonf_subsystem.h"
+#include "rfc5444/rfc5444.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_timer.h"
+
+#include "nhdp/nhdp.h"
+#include "nhdp/nhdp_db.h"
+#include "nhdp/nhdp_domain.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "mpr/mpr.h"
+
+#include "neighbor-graph-flooding.h"
+#include "neighbor-graph-routing.h"
+#include "selection-rfc7181.h"
+
+/* FIXME remove unneeded includes */
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+static void _cb_update_mpr(void);
+static void _cb_cfg_changed(void);
+
+/* plugin declaration */
+static struct cfg_schema_entry _mpr_rfc_entries[] = {
+  /* FIXME Shouldn't this be configurable per domain? What about flooding 
+   * willingness? */
+  CFG_MAP_INT32_MINMAX(nhdp_domain_mpr, willingness, "willingness",
+      RFC7181_WILLINGNESS_DEFAULT_STRING, "Routing willingness", 0, false,
+      RFC7181_WILLINGNESS_MIN, RFC7181_WILLINGNESS_MAX),
+  CFG_MAP_BOOL(nhdp_domain_mpr, mpr_start, "mpr_start",
+      "false", "Default value for neighbor MPR setting"),
+  CFG_MAP_BOOL(nhdp_domain_mpr, mprs_start, "mprs_start",
+      "false", "Default value for local MPR (selector) setting"),
+};
+
+static struct cfg_schema_section _mpr_rfc_section = {
+  .type = OONF_MPR_SUBSYSTEM,
+  .cb_delta_handler = _cb_cfg_changed,
+  .entries = _mpr_rfc_entries,
+  .entry_count = ARRAYSIZE(_mpr_rfc_entries),
+};
+
+static const char *_dependencies[] = {
+  OONF_CLASS_SUBSYSTEM,
+  OONF_TIMER_SUBSYSTEM,
+};
+struct oonf_subsystem olsrv2_mpr_subsystem = {
+  .name = OONF_MPR_SUBSYSTEM,
+  .dependencies = _dependencies,
+  .dependencies_count = ARRAYSIZE(_dependencies),
+  .descr = "OLSRv2 MPR Plugin",
+  .author = "Jonathan Kirchhoff",
+  .cfg_section = &_mpr_rfc_section,
+  .init = _init,
+  .cleanup = _cleanup,
+};
+DECLARE_OONF_PLUGIN(olsrv2_mpr_subsystem);
+
+static struct nhdp_domain_mpr _mpr_handler = {
+  .name = OONF_MPR_SUBSYSTEM,
+  .update_mpr = _cb_update_mpr,
+  .willingness = RFC7181_WILLINGNESS_DEFAULT,
+  .mpr_start = false,
+  .mprs_start = false,
+};
+
+/**
+ * Initialize plugin
+ * @return -1 if an error happened, 0 otherwise
+ */
+static int
+_init(void) {
+  if (nhdp_domain_mpr_add(&_mpr_handler)) {
+    return -1;
+  }
+
+  nhdp_domain_set_flooding_mpr(&_mpr_handler, 0);
+
+  OONF_DEBUG(LOG_MPR, "Initializing");
+  return 0;
+}
+
+/**
+ * Cleanup plugin
+ */
+static void
+_cleanup(void) {
+}
+
+/**
+ * Updates the current routing MPR selection in the NHDP database
+ * @param current_mpr_data
+ */
+static void
+_update_nhdp_routing(struct neighbor_graph *graph) {
+  struct nhdp_link *lnk;
+  struct n1_node *current_mpr_node;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str buf1;
+#endif
+
+  OONF_DEBUG(LOG_MPR, "Updating ROUTING MPRs");
+  
+  list_for_each_element(&nhdp_link_list, lnk, _global_node) {
+    lnk->neigh->_domaindata[0].neigh_is_mpr = false;
+    current_mpr_node = avl_find_element(&graph->set_mpr,
+        &lnk->neigh->originator,
+        current_mpr_node, _avl_node);
+    if (current_mpr_node != NULL) {
+      OONF_DEBUG(LOG_MPR, "Processing MPR node %s",
+          netaddr_to_string(&buf1, &current_mpr_node->addr));
+      lnk->neigh->_domaindata[0].neigh_is_mpr = true;
+    }
+  }
+}
+
+/**
+ * Updates the current flooding MPR selection in the NHDP database
+ * @param current_mpr_data
+ */
+static void
+_update_nhdp_flooding(struct neighbor_graph *graph) {
+  struct nhdp_link *current_link;
+  struct n1_node *current_mpr_node;
+#ifdef OONF_LOG_DEBUG_INFO
+  struct netaddr_str buf1;
+#endif
+
+  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
+
+  list_for_each_element(&nhdp_link_list, current_link, _global_node) {
+    current_mpr_node = avl_find_element(&graph->set_mpr,
+        &current_link->neigh->originator,
+        current_mpr_node, _avl_node);
+    if (current_mpr_node != NULL) {
+      OONF_DEBUG(LOG_MPR, "Processing MPR node %s",
+          netaddr_to_string(&buf1, &current_mpr_node->addr));
+      current_link->neigh->neigh_is_flooding_mpr = true;
+    }
+  }
+}
+
+/**
+ * Updates the current flooding MPR selection in the NHDP database
+ * @param current_mpr_data
+ */
+static void
+_clear_nhdp_flooding(void) {
+  struct nhdp_link *current_link;
+
+  OONF_DEBUG(LOG_MPR, "Updating FLOODING MPRs");
+
+  list_for_each_element(&nhdp_link_list, current_link, _global_node) {
+    current_link->neigh->neigh_is_flooding_mpr = false;
+  }
+}
+
+static void
+_update_flooding_mpr(void) {
+  struct mpr_flooding_data flooding_data;
+
+  memset(&flooding_data, 0, sizeof(flooding_data));
+  
+  /* FIXME Currently, the flooding set is calculated incrementally (i.e. 
+   in a coordinated way as suggested by RFC 7181; however, this should
+   be configurable (and other selection algorithms might not be compatible
+   with this approach).
+   */
+  /* FIXME How to support the coordination flooding and routing MPRs 
+   * selection? */
+  /* calculate flooding MPRs */
+  _clear_nhdp_flooding();
+  avl_for_each_element(&nhdp_interface_tree, flooding_data.current_interface, _node) {
+    OONF_DEBUG(LOG_MPR, "Calculating flooding MPRs for interface %s",
+        nhdp_interface_get_name(flooding_data.current_interface));
+    
+    mpr_calculate_neighbor_graph_flooding(
+        nhdp_domain_get_flooding_mpr()->domain, &flooding_data);
+    mpr_calculate_mpr_rfc7181(nhdp_domain_get_flooding_mpr()->domain,
+        &flooding_data.neigh_graph);
+    mpr_print_sets(&flooding_data.neigh_graph);
+    _update_nhdp_flooding(&flooding_data.neigh_graph);
+  }
+
+  /* free memory */
+  mpr_clear_neighbor_graph(&flooding_data.neigh_graph);
+}
+
+static void
+_update_routing_mpr(void) {
+  struct neighbor_graph routing_graph;
+  struct nhdp_domain *domain;
+
+  list_for_each_element(&nhdp_domain_list, domain, _node) {
+    memset(&routing_graph, 0, sizeof(routing_graph));
+
+    mpr_calculate_neighbor_graph_routing(domain, &routing_graph);
+    mpr_calculate_mpr_rfc7181(domain, &routing_graph);
+    mpr_print_sets(&routing_graph);
+    _update_nhdp_routing(&routing_graph);
+  }
+}
+
+/**
+ * Callback triggered when an MPR update is required
+ */
+static void
+_cb_update_mpr(void) {
+  OONF_DEBUG(LOG_MPR, "Recalculating MPRs");
+
+  /* calculate flooding MPRs */
+  _update_flooding_mpr();
+  
+  /* calculate routing MPRs */
+  _update_routing_mpr();
+
+  OONF_DEBUG(LOG_MPR, "Finished recalculating MPRs");
+}
+
+/**
+ * Callback triggered when configuration changes
+ * 
+ * FIXME Currently a stub
+ */
+static void
+_cb_cfg_changed(void) {
+  OONF_DEBUG(LOG_MPR, "Config changed");
+
+  if (cfg_schema_tobin(&_mpr_handler, _mpr_rfc_section.post,
+      _mpr_rfc_entries, ARRAYSIZE(_mpr_rfc_entries))) {
+    OONF_WARN(LOG_MPR, "Cannot convert configuration for "
+        OONF_MPR_SUBSYSTEM);
+    return;
+  }
+}
+
+#if 0
+
+/**
+ * Validate the MPR set according to section 18.3 (draft 19)
+ * @param current_mpr_data
+ * @return 
+ */
+void
+_validate_mpr_set(struct common_data *mpr_data) {
+  struct n1_node *node_n1;
+  struct addr_node *n2_addr;
+  uint32_t d_y_n1, d_y_mpr;
+
+  OONF_DEBUG(LOG_MPR, "Validating MPR set");
+
+  /* 
+   * First property: If x in N1 has W(x) = WILL_ALWAYS then x is in M. 
+   */
+  avl_for_each_element(&mpr_data->set_n1, node_n1,
+      _avl_node) {
+    if (node_n1->neigh->flooding_willingness
+        == RFC5444_WILLINGNESS_ALWAYS) {
+      assert(_is_mpr(mpr_data, &node_n1->addr));
+    }
+  }
+
+  /*
+   * Second property: For any y in N2 that does not have a defined d1(y), 
+   * there is at least one element in M that is also in N1(y). This is 
+   * equivalent to the requirement that d(y, M) is defined.
+   */
+  avl_for_each_element(&mpr_data->set_n2, n2_addr, _avl_node) {
+    assert(_calculate_d_of_y_s(mpr_data, n2_addr, &mpr_data->set_mpr)
+        != RFC5444_METRIC_INFINITE);
+  }
+
+  /*
+   * Third property: For any y in N2, d(y,M) = d(y, N1).
+   */
+  avl_for_each_element(&mpr_data->set_n2, n2_addr, _avl_node) {
+    d_y_n1 = _calculate_d_of_y_s(mpr_data, n2_addr, &mpr_data->set_n1);
+    d_y_mpr = _calculate_d_of_y_s(mpr_data, n2_addr, &mpr_data->set_mpr);
+    assert(d_y_n1 == d_y_mpr);
+  }
+}
+
+
+#endif
diff --git a/src-plugins/nhdp/mpr/mpr.h b/src-plugins/nhdp/mpr/mpr.h
new file mode 100644 (file)
index 0000000..8a6cdaa
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef MPR_H_
+#define MPR_H_
+
+#include "neighbor-graph.h"
+#include "neighbor-graph-flooding.h"
+
+#include "common/common_types.h"
+#include "core/oonf_subsystem.h"
+#include "common/list.h"
+
+/* definitions and constants */
+#define OONF_MPR_SUBSYSTEM "mpr"
+
+#define LOG_MPR olsrv2_mpr_subsystem.logging
+EXPORT extern struct oonf_subsystem olsrv2_mpr_subsystem;
+
+#endif /* MPR_H_ */
diff --git a/src-plugins/nhdp/mpr/neighbor-graph-flooding.c b/src-plugins/nhdp/mpr/neighbor-graph-flooding.c
new file mode 100644 (file)
index 0000000..e345f0c
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+
+#include "neighbor-graph-flooding.h"
+#include "neighbor-graph.h"
+#include "mpr.h"
+
+#include "nhdp/nhdp.h"
+#include "nhdp/nhdp_db.h"
+#include "nhdp/nhdp_domain.h"
+#include "rfc5444/rfc5444.h"
+#include "nhdp/nhdp_interfaces.h"
+
+#include "common/common_types.h"
+#include "common/autobuf.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "common/container_of.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_logging.h"
+#include "rfc5444/rfc5444.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_timer.h"
+
+/* FIXME remove unneeded includes */
+
+static uint32_t _calculate_d1_x(struct nhdp_domain *domain, struct n1_node *x);
+static uint32_t _calculate_d2_x_y(struct nhdp_domain *domain,
+    struct n1_node *x, struct addr_node *y);
+static uint32_t _calculate_d_x_y(struct nhdp_domain *domain,
+    struct n1_node *x, struct addr_node *y);
+#if 0
+static uint32_t _calculate_d1_of_y(struct mpr_flooding_data *data, struct addr_node *y);
+#endif
+static uint32_t _calculate_d1_x_of_n2_addr(struct nhdp_domain *domain,
+    struct neighbor_graph *graph, struct netaddr *addr);
+static void _calculate_n1(struct nhdp_domain *domain, struct mpr_flooding_data *data);
+static void _calculate_n2(struct nhdp_domain *domain, struct mpr_flooding_data *data);
+
+static bool _is_allowed_link_tuple(struct nhdp_domain *domain,
+    struct nhdp_interface *current_interface, struct nhdp_link *lnk);
+static uint32_t _get_willingness_n1(struct nhdp_domain *, struct n1_node *node);
+
+static struct neighbor_graph_interface _api_interface = {
+  .is_allowed_link_tuple     = _is_allowed_link_tuple,
+  .calculate_d1_x_of_n2_addr = _calculate_d1_x_of_n2_addr,
+  .calculate_d_x_y           = _calculate_d_x_y,
+  .calculate_d2_x_y          = _calculate_d2_x_y,
+  .get_willingness_n1        = _get_willingness_n1,
+};
+
+/**
+ * Check if a given tuple is "reachable" according to section 18.4
+ * @param mpr_data
+ * @param link
+ * @return 
+ */
+static bool
+_is_reachable_link_tuple(struct nhdp_domain *domain,
+    struct nhdp_interface *current_interface, struct nhdp_link *lnk) {
+  struct nhdp_link_domaindata *linkdata;
+
+  linkdata = nhdp_domain_get_linkdata(domain, lnk);
+  if (lnk->local_if == current_interface
+      && linkdata->metric.out != RFC7181_METRIC_INFINITE
+      && lnk->status == NHDP_LINK_SYMMETRIC) {
+    return true;
+  }
+  return false;
+}
+
+/**
+ * Check if a link tuple is "allowed" according to section 18.4
+ * @param mpr_data
+ * @param link
+ * @return 
+ */
+static bool
+_is_allowed_link_tuple(struct nhdp_domain *domain,
+    struct nhdp_interface *current_interface, struct nhdp_link *lnk) {
+  if (_is_reachable_link_tuple(domain, current_interface, lnk)
+      && lnk->neigh->flooding_willingness > RFC7181_WILLINGNESS_NEVER) {
+    return true;
+  }
+  return false;
+}
+
+static bool
+_is_allowed_2hop_tuple(struct nhdp_domain *domain,
+    struct nhdp_interface *current_interface, struct nhdp_l2hop *two_hop) {
+  struct nhdp_l2hop_domaindata *twohopdata;
+
+  twohopdata = nhdp_domain_get_l2hopdata(domain, two_hop);
+  if (two_hop->link->local_if == current_interface
+      && twohopdata->metric.out != RFC7181_METRIC_INFINITE) {
+    return true;
+  }
+  return false;
+}
+
+static uint32_t
+_calculate_d1_x(struct nhdp_domain *domain, struct n1_node *x) {
+  struct nhdp_link_domaindata *linkdata;
+
+  linkdata = nhdp_domain_get_linkdata(domain, x->link);
+  return linkdata->metric.out;
+}
+
+static uint32_t
+_calculate_d2_x_y(struct nhdp_domain *domain,
+    struct n1_node *x, struct addr_node *y) {
+  struct nhdp_l2hop *tmp_l2hop;
+  struct nhdp_l2hop_domaindata *twohopdata;
+
+  /* find the corresponding 2-hop entry, if it exists */
+  tmp_l2hop = avl_find_element(&x->link->_2hop,
+      &y->addr, tmp_l2hop, _link_node);
+  if (tmp_l2hop) {
+    twohopdata = nhdp_domain_get_l2hopdata(domain, tmp_l2hop);
+    return twohopdata->metric.out;
+  }
+  return RFC7181_METRIC_INFINITE;
+}
+
+static uint32_t
+_calculate_d_x_y(struct nhdp_domain *domain,
+    struct n1_node *x, struct addr_node *y) {
+  return _calculate_d1_x(domain, x) + _calculate_d2_x_y(domain, x, y);
+}
+
+#if 0
+/**
+ * Calculate d1(y) according to section 18.2 (draft 19)
+ * @param mpr_data
+ * @return 
+ */
+uint32_t
+_calculate_d1_of_y(struct mpr_flooding_data *data, struct addr_node *y) {
+  struct n1_node *node_n1;
+  struct nhdp_laddr *laddr;
+
+  /* find the N1 neighbor corresponding to this address, if it exists */
+  avl_for_each_element(&data->neigh_graph.set_n1, node_n1, _avl_node) {
+    laddr = avl_find_element(&node_n1->link->_addresses, y,
+        laddr, _link_node);
+    if (laddr != NULL) {
+      return node_n1->link->_domaindata[0].metric.out;
+    }
+  }
+  return RFC5444_METRIC_INFINITE;
+}
+#endif
+
+/**
+ * Calculate d1(x) according to section 18.2 (draft 19)
+ * @param mpr_data
+ * @param addr
+ * @return 
+ */
+uint32_t
+_calculate_d1_x_of_n2_addr(struct nhdp_domain *domain,
+    struct neighbor_graph *graph, struct netaddr *addr) {
+  struct n1_node *node_n1;
+  struct nhdp_naddr *naddr;
+  struct nhdp_link_domaindata *linkdata;
+
+  // FIXME Implementation correct?!?!
+
+  avl_for_each_element(&graph->set_n1, node_n1, _avl_node) {
+    /* check if the address provided corresponds to this node */
+    naddr = avl_find_element(&node_n1->neigh->_neigh_addresses,
+        addr, naddr, _neigh_node);
+    if (naddr) {
+      linkdata = nhdp_domain_get_linkdata(domain, node_n1->link);
+      return linkdata->metric.out;
+    }
+  }
+
+  return RFC7181_METRIC_INFINITE;
+}
+
+/**
+ * Calculate N1
+ * @param interf
+ */
+static void
+_calculate_n1(struct nhdp_domain *domain, struct mpr_flooding_data *data) {
+  struct nhdp_link *lnk;
+
+  OONF_DEBUG(LOG_MPR, "Calculate N1 for interface %s",
+      nhdp_interface_get_name(data->current_interface));