Rewrite of DLEP for compatibility with DLEP-15
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 8 Jul 2015 12:57:00 +0000 (14:57 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Wed, 8 Jul 2015 12:57:00 +0000 (14:57 +0200)
New code should be much easier to extend
Add dlep-router application

35 files changed:
src-plugins/generic/dlep/CMakeLists.txt
src-plugins/generic/dlep/dlep_base/dlep_base.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_base/dlep_base.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_base/dlep_base_radio.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_base/dlep_base_radio.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_base/dlep_base_router.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_base/dlep_base_router.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_extension.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_extension.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_iana.h
src-plugins/generic/dlep/dlep_interface.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_interface.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_parser.c [deleted file]
src-plugins/generic/dlep/dlep_parser.h [deleted file]
src-plugins/generic/dlep/dlep_reader.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_reader.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_session.c [new file with mode: 0644]
src-plugins/generic/dlep/dlep_session.h [new file with mode: 0644]
src-plugins/generic/dlep/dlep_static_data.c [deleted file]
src-plugins/generic/dlep/dlep_static_data.h [deleted file]
src-plugins/generic/dlep/dlep_writer.c
src-plugins/generic/dlep/dlep_writer.h
src-plugins/generic/dlep/radio/dlep_radio.c
src-plugins/generic/dlep/radio/dlep_radio_interface.c
src-plugins/generic/dlep/radio/dlep_radio_interface.h
src-plugins/generic/dlep/radio/dlep_radio_session.c
src-plugins/generic/dlep/radio/dlep_radio_session.h
src-plugins/generic/dlep/router/dlep_router.c
src-plugins/generic/dlep/router/dlep_router_interface.c
src-plugins/generic/dlep/router/dlep_router_interface.h
src-plugins/generic/dlep/router/dlep_router_session.c
src-plugins/generic/dlep/router/dlep_router_session.h
src/CMakeLists.txt
src/dlep-router/CMakeLists.txt [new file with mode: 0644]
src/olsrd2/CMakeLists.txt

index ac5b31b..d58e17f 100644 (file)
@@ -1,13 +1,18 @@
 # set source files
-SET (radio_only_source  radio/dlep_radio.c
+SET (radio_only_source  dlep_base/dlep_base_radio.c
+                        radio/dlep_radio.c
                         radio/dlep_radio_interface.c
                         radio/dlep_radio_session.c) 
-SET (router_only_source router/dlep_router.c
+SET (router_only_source dlep_base/dlep_base_router.c
+                        router/dlep_router.c
                         router/dlep_router_interface.c
                         router/dlep_router_session.c)
-SET (common_source      dlep_parser.c
-                        dlep_writer.c
-                        dlep_static_data.c)
+SET (common_source      dlep_base/dlep_base.c
+                        dlep_extension.c
+                        dlep_interface.c
+                        dlep_session.c
+                        dlep_reader.c
+                        dlep_writer.c)
 
 # sources/includes for dlep_radio                    
 SET (radio_source       ${common_source}
diff --git a/src-plugins/generic/dlep/dlep_base/dlep_base.c b/src-plugins/generic/dlep/dlep_base/dlep_base.c
new file mode 100644 (file)
index 0000000..b824656
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * dlep_radio_base_extension.c
+ *
+ *  Created on: Jun 25, 2015
+ *      Author: rogge
+ */
+
+#include "../dlep_base/dlep_base.h"
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/autobuf.h"
+#include "core/oonf_logging.h"
+#include "subsystems/oonf_timer.h"
+
+#include "dlep/dlep_iana.h"
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_reader.h"
+#include "dlep/dlep_writer.h"
+#include "dlep/dlep_base/dlep_base.h"
+
+static void _cb_local_heartbeat(void *);
+static void _cb_remote_heartbeat(void *);
+
+/* peer discovery */
+static const uint16_t _peer_discovery_tlvs[] = {
+};
+static const uint16_t _peer_discovery_mandatory[] = {
+};
+
+/* peer offer */
+static const uint16_t _peer_offer_tlvs[] = {
+    DLEP_PEER_TYPE_TLV,
+    DLEP_IPV4_CONPOINT_TLV,
+    DLEP_IPV6_CONPOINT_TLV,
+};
+static const uint16_t _peer_offer_mandatory[] = {
+};
+
+/* peer initialization */
+static const uint16_t _peer_init_tlvs[] = {
+    DLEP_HEARTBEAT_INTERVAL_TLV,
+    DLEP_PEER_TYPE_TLV,
+    DLEP_EXTENSIONS_SUPPORTED_TLV,
+};
+static const uint16_t _peer_init_mandatory[] = {
+    DLEP_HEARTBEAT_INTERVAL_TLV,
+};
+
+/* peer initialization ack */
+static const uint16_t _peer_initack_tlvs[] = {
+    DLEP_HEARTBEAT_INTERVAL_TLV,
+    DLEP_MDRR_TLV,
+    DLEP_MDRT_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+    DLEP_RESR_TLV,
+    DLEP_REST_TLV,
+    DLEP_RLQR_TLV,
+    DLEP_RLQT_TLV,
+    DLEP_STATUS_TLV,
+    DLEP_PEER_TYPE_TLV,
+    DLEP_EXTENSIONS_SUPPORTED_TLV,
+};
+static const uint16_t _peer_initack_mandatory[] = {
+    DLEP_HEARTBEAT_INTERVAL_TLV,
+    DLEP_MDRR_TLV,
+    DLEP_MDRT_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+};
+
+/* peer update */
+static const uint16_t _peer_update_tlvs[] = {
+    DLEP_MDRR_TLV,
+    DLEP_MDRT_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+    DLEP_RESR_TLV,
+    DLEP_REST_TLV,
+    DLEP_RLQR_TLV,
+    DLEP_RLQT_TLV,
+    DLEP_IPV4_ADDRESS_TLV,
+    DLEP_IPV6_ADDRESS_TLV,
+};
+static const uint16_t _peer_update_duplicates[] = {
+    DLEP_IPV4_ADDRESS_TLV,
+    DLEP_IPV6_ADDRESS_TLV,
+};
+
+/* peer update ack */
+static const uint16_t _peer_updateack_tlvs[] = {
+    DLEP_STATUS_TLV,
+};
+
+/* peer termination */
+static const uint16_t _peer_termination_tlvs[] = {
+    DLEP_STATUS_TLV,
+};
+
+/* peer termination ack */
+static const uint16_t _peer_terminationack_tlvs[] = {
+    DLEP_STATUS_TLV,
+};
+
+/* destination up */
+static const uint16_t _dst_up_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+    DLEP_MDRR_TLV,
+    DLEP_MDRT_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+    DLEP_RESR_TLV,
+    DLEP_REST_TLV,
+    DLEP_RLQR_TLV,
+    DLEP_RLQT_TLV,
+    DLEP_IPV4_ADDRESS_TLV,
+    DLEP_IPV6_ADDRESS_TLV,
+    DLEP_IPV4_SUBNET_TLV,
+    DLEP_IPV6_SUBNET_TLV,
+};
+static const uint16_t _dst_up_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+static const uint16_t _dst_up_duplicates[] = {
+    DLEP_IPV4_ADDRESS_TLV,
+    DLEP_IPV6_ADDRESS_TLV,
+    DLEP_IPV4_SUBNET_TLV,
+    DLEP_IPV6_SUBNET_TLV,
+};
+
+/* destination up ack */
+static const uint16_t _dst_up_ack_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+    DLEP_STATUS_TLV,
+};
+static const uint16_t _dst_up_ack_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+
+/* destination down */
+static const uint16_t _dst_down_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+static const uint16_t _dst_down_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+
+/* destination down ack */
+static const uint16_t _dst_down_ack_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+    DLEP_STATUS_TLV,
+};
+static const uint16_t _dst_down_ack_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+
+/* destination update */
+static const uint16_t _dst_update_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+    DLEP_MDRR_TLV,
+    DLEP_MDRT_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+    DLEP_RESR_TLV,
+    DLEP_REST_TLV,
+    DLEP_RLQR_TLV,
+    DLEP_RLQT_TLV,
+    DLEP_IPV4_ADDRESS_TLV,
+    DLEP_IPV6_ADDRESS_TLV,
+    DLEP_IPV4_SUBNET_TLV,
+    DLEP_IPV6_SUBNET_TLV,
+};
+static const uint16_t _dst_update_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+static const uint16_t _dst_update_duplicates[] = {
+    DLEP_IPV4_ADDRESS_TLV,
+    DLEP_IPV6_ADDRESS_TLV,
+    DLEP_IPV4_SUBNET_TLV,
+    DLEP_IPV6_SUBNET_TLV,
+};
+
+/* link characteristics request */
+static const uint16_t _linkchar_req_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+    DLEP_LINK_CHAR_ACK_TIMER_TLV,
+};
+static const uint16_t _linkchar_req_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+
+/* link characteristics ack */
+static const uint16_t _linkchar_ack_tlvs[] = {
+    DLEP_MAC_ADDRESS_TLV,
+    DLEP_MDRR_TLV,
+    DLEP_MDRT_TLV,
+    DLEP_CDRR_TLV,
+    DLEP_CDRT_TLV,
+    DLEP_LATENCY_TLV,
+    DLEP_RESR_TLV,
+    DLEP_REST_TLV,
+    DLEP_RLQR_TLV,
+    DLEP_RLQT_TLV,
+    DLEP_STATUS_TLV,
+};
+static const uint16_t _linkchar_ack_mandatory[] = {
+    DLEP_MAC_ADDRESS_TLV,
+};
+
+/* supported signals of this extension */
+static struct dlep_extension_signal _signals[] = {
+    {
+        .id = DLEP_PEER_DISCOVERY,
+        .supported_tlvs = _peer_discovery_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_discovery_tlvs),
+        .mandatory_tlvs = _peer_discovery_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_peer_discovery_mandatory),
+    },
+    {
+        .id = DLEP_PEER_OFFER,
+        .supported_tlvs = _peer_offer_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_offer_tlvs),
+        .mandatory_tlvs = _peer_offer_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_peer_offer_mandatory),
+    },
+    {
+        .id = DLEP_PEER_DISCOVERY,
+        .supported_tlvs = _peer_discovery_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_discovery_tlvs),
+        .mandatory_tlvs = _peer_discovery_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_peer_discovery_mandatory),
+    },
+    {
+        .id = DLEP_PEER_OFFER,
+        .supported_tlvs = _peer_offer_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_offer_tlvs),
+        .mandatory_tlvs = _peer_offer_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_peer_offer_mandatory),
+    },
+    {
+        .id = DLEP_PEER_INITIALIZATION,
+        .supported_tlvs = _peer_init_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_init_tlvs),
+        .mandatory_tlvs = _peer_init_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_peer_init_mandatory),
+    },
+    {
+        .id = DLEP_PEER_INITIALIZATION_ACK,
+        .supported_tlvs = _peer_initack_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_initack_tlvs),
+        .mandatory_tlvs = _peer_initack_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_peer_initack_mandatory),
+    },
+    {
+        .id = DLEP_PEER_UPDATE,
+        .supported_tlvs = _peer_update_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_update_tlvs),
+        .duplicate_tlvs = _peer_update_duplicates,
+        .duplicate_tlv_count = ARRAYSIZE(_peer_update_duplicates),
+    },
+    {
+        .id = DLEP_PEER_UPDATE_ACK,
+        .supported_tlvs = _peer_updateack_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_updateack_tlvs),
+    },
+    {
+        .id = DLEP_PEER_TERMINATION,
+        .supported_tlvs = _peer_termination_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_termination_tlvs),
+    },
+    {
+        .id = DLEP_PEER_TERMINATION_ACK,
+        .supported_tlvs = _peer_terminationack_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_peer_terminationack_tlvs),
+    },
+    {
+        .id = DLEP_DESTINATION_UP,
+        .supported_tlvs = _dst_up_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_dst_up_tlvs),
+        .mandatory_tlvs = _dst_up_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_dst_up_mandatory),
+        .duplicate_tlvs = _dst_up_duplicates,
+        .duplicate_tlv_count = ARRAYSIZE(_dst_up_duplicates),
+    },
+    {
+        .id = DLEP_DESTINATION_UP_ACK,
+        .supported_tlvs = _dst_up_ack_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_dst_up_ack_tlvs),
+        .mandatory_tlvs = _dst_up_ack_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_dst_up_ack_mandatory),
+    },
+    {
+        .id = DLEP_DESTINATION_DOWN,
+        .supported_tlvs = _dst_down_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_dst_down_tlvs),
+        .mandatory_tlvs = _dst_down_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_dst_down_mandatory),
+    },
+    {
+        .id = DLEP_DESTINATION_DOWN_ACK,
+        .supported_tlvs = _dst_down_ack_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_dst_down_ack_tlvs),
+        .mandatory_tlvs = _dst_down_ack_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_dst_down_ack_mandatory),
+    },
+    {
+        .id = DLEP_DESTINATION_UPDATE,
+        .supported_tlvs = _dst_update_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_dst_update_tlvs),
+        .mandatory_tlvs = _dst_update_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_dst_update_mandatory),
+        .duplicate_tlvs = _dst_update_duplicates,
+        .duplicate_tlv_count = ARRAYSIZE(_dst_update_duplicates),
+    },
+    {
+        .id = DLEP_HEARTBEAT,
+    },
+    {
+        .id = DLEP_LINK_CHARACTERISTICS_REQUEST,
+        .supported_tlvs = _linkchar_req_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_linkchar_req_tlvs),
+        .mandatory_tlvs = _linkchar_req_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_linkchar_req_mandatory),
+    },
+    {
+        .id = DLEP_LINK_CHARACTERISTICS_ACK,
+        .supported_tlvs = _linkchar_ack_tlvs,
+        .supported_tlv_count = ARRAYSIZE(_linkchar_ack_tlvs),
+        .mandatory_tlvs = _linkchar_ack_mandatory,
+        .mandatory_tlv_count = ARRAYSIZE(_linkchar_ack_mandatory),
+    },
+};
+
+/* supported TLVs of this extension */
+static struct dlep_extension_tlv _tlvs[] = {
+    { DLEP_STATUS_TLV, 1,65535 },
+    { DLEP_IPV4_CONPOINT_TLV, 6,6 },
+    { DLEP_IPV6_CONPOINT_TLV, 18,18 },
+    { DLEP_PEER_TYPE_TLV, 1,255 },
+    { DLEP_HEARTBEAT_INTERVAL_TLV, 2,2 },
+    { DLEP_EXTENSIONS_SUPPORTED_TLV, 2, 65534 },
+    { DLEP_MAC_ADDRESS_TLV, 6,8 },
+    { DLEP_IPV4_ADDRESS_TLV, 5,5 },
+    { DLEP_IPV6_ADDRESS_TLV, 17,17 },
+    { DLEP_IPV4_SUBNET_TLV, 5,5 },
+    { DLEP_IPV6_SUBNET_TLV, 17,17 },
+    { DLEP_MDRR_TLV, 8,8 },
+    { DLEP_MDRT_TLV, 8,8 },
+    { DLEP_CDRR_TLV, 8,8 },
+    { DLEP_CDRT_TLV, 8,8 },
+    { DLEP_LATENCY_TLV, 8,8 },
+    { DLEP_RESR_TLV, 1,1 },
+    { DLEP_REST_TLV, 1,1 },
+    { DLEP_RLQR_TLV, 1,1 },
+    { DLEP_RLQT_TLV, 1,1 },
+    { DLEP_LINK_CHAR_ACK_TIMER_TLV, 1,1 },
+};
+
+static struct dlep_neighbor_mapping _neigh_mappings[] = {
+    {
+        .dlep     = DLEP_MDRR_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_RX_MAX_BITRATE,
+        .length   = 8,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_MDRT_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_TX_MAX_BITRATE,
+        .length   = 8,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_CDRR_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_RX_BITRATE,
+        .length   = 8,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_CDRT_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_TX_BITRATE,
+        .length   = 8,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_LATENCY_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_LATENCY,
+        .length   = 8,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_RESR_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_RX_RESOURCES,
+        .length   = 1,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_REST_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_TX_RESOURCES,
+        .length   = 1,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_RLQR_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_RX_RLQ,
+        .length   = 1,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+    {
+        .dlep     = DLEP_RLQT_TLV,
+        .layer2   = OONF_LAYER2_NEIGH_TX_RLQ,
+        .length   = 1,
+        .from_tlv = dlep_reader_map_identity,
+        .to_tlv   = dlep_writer_map_identity,
+    },
+};
+
+/* DLEP base extension, radio side */
+static struct dlep_extension _base = {
+  .id = DLEP_EXTENSION_BASE,
+  .name = "base",
+
+  .signals = _signals,
+  .signal_count = ARRAYSIZE(_signals),
+  .tlvs = _tlvs,
+  .tlv_count = ARRAYSIZE(_tlvs),
+  .neigh_mapping = _neigh_mappings,
+  .neigh_mapping_count = ARRAYSIZE(_neigh_mappings),
+};
+
+static struct oonf_timer_class _local_heartbeat_class = {
+  .name = "dlep local heartbeat",
+  .callback = _cb_local_heartbeat,
+  .periodic = true,
+};
+static struct oonf_timer_class _remote_heartbeat_class = {
+  .name = "dlep remote heartbeat",
+  .callback = _cb_remote_heartbeat,
+};
+
+struct dlep_extension *
+dlep_base_init(void) {
+  if (_base._node.key) {
+    return &_base;
+  }
+
+  _base._node.key = &_base.id;
+  avl_insert(dlep_extension_get_tree(), &_base._node);
+
+  oonf_timer_add(&_local_heartbeat_class);
+  oonf_timer_add(&_remote_heartbeat_class);
+  return &_base;
+}
+
+void
+dlep_base_start_local_heartbeat(struct dlep_session *session) {
+  /* timer for local heartbeat generation */
+  session->local_event_timer.class = &_local_heartbeat_class;
+  session->local_event_timer.cb_context = session;
+  oonf_timer_set(&session->local_event_timer,
+      session->cfg.heartbeat_interval);
+}
+
+void
+dlep_base_start_remote_heartbeat(struct dlep_session *session) {
+  /* timeout for remote heartbeats */
+  session->remote_heartbeat_timeout.class = &_remote_heartbeat_class;
+  session->remote_heartbeat_timeout.cb_context = session;
+  oonf_timer_set(&session->remote_heartbeat_timeout,
+      session->remote_heartbeat_interval * 2);
+}
+
+void
+dlep_base_stop_timers(struct dlep_session *session) {
+  OONF_DEBUG(session->log_source, "Cleanup base session");
+  oonf_timer_stop(&session->local_event_timer);
+  oonf_timer_stop(&session->remote_heartbeat_timeout);
+}
+
+enum dlep_status
+dlep_base_print_status(struct dlep_session *session) {
+  enum dlep_status status;
+  char text[256];
+
+  if (!dlep_reader_status(&status, text, sizeof(text), session, NULL)) {
+    OONF_DEBUG(session->log_source,
+        "Status %d received: %s", status, text);
+
+    return status;
+  }
+  return DLEP_STATUS_OKAY;
+}
+
+void
+dlep_base_print_peer_type(struct dlep_session *session) {
+  char text[256];
+
+  if (!dlep_reader_peer_type(text, sizeof(text), session, NULL)) {
+    OONF_DEBUG(session->log_source,
+        "Remote peer type: %s", text);
+  }
+}
+
+int
+dlep_base_process_peer_termination(struct dlep_session *session) {
+  dlep_base_print_status(session);
+
+  return dlep_session_generate_signal(session, DLEP_PEER_TERMINATION_ACK, NULL);
+}
+
+int
+dlep_base_process_peer_termination_ack(struct dlep_session *session) {
+  if (session->cb_end_session) {
+    session->cb_end_session(session);
+  }
+  return 0;
+}
+
+int
+dlep_base_process_heartbeat(struct dlep_session *session) {
+  /* just restart the timeout with the same period */
+  oonf_timer_set(&session->remote_heartbeat_timeout,
+      session->remote_heartbeat_interval * 2);
+  return 0;
+}
+
+int
+dlep_base_write_mac_only(
+    struct dlep_session *session, const struct netaddr *neigh) {
+  if (dlep_writer_add_mac_tlv(&session->writer, neigh)) {
+    return -1;
+  }
+  return 0;
+}
+
+static void
+_cb_local_heartbeat(void *ptr) {
+  struct dlep_session *session = ptr;
+
+  dlep_session_generate_signal(session, DLEP_HEARTBEAT, NULL);
+  session->cb_send_buffer(session, 0);
+}
+
+static void
+_cb_remote_heartbeat(void *ptr) {
+  struct dlep_session *session = ptr;
+
+  /* stop local heartbeats */
+  oonf_timer_stop(&session->local_event_timer);
+
+  /* terminate session */
+  dlep_session_generate_signal(session, DLEP_PEER_TERMINATION, NULL);
+  session->next_signal = DLEP_PEER_TERMINATION_ACK;
+}
diff --git a/src-plugins/generic/dlep/dlep_base/dlep_base.h b/src-plugins/generic/dlep/dlep_base/dlep_base.h
new file mode 100644 (file)
index 0000000..ed75119
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * dlep_base.h
+ *
+ *  Created on: Jun 29, 2015
+ *      Author: rogge
+ */
+
+#ifndef _DLEP_BASE_H_
+#define _DLEP_BASE_H_
+
+#include "common/common_types.h"
+#include "core/oonf_logging.h"
+
+#include "dlep/dlep_iana.h"
+#include "dlep/dlep_session.h"
+
+struct dlep_extension *dlep_base_init(void);
+void dlep_base_start_local_heartbeat(struct dlep_session *session);
+void dlep_base_start_remote_heartbeat(struct dlep_session *session);
+void dlep_base_stop_timers(struct dlep_session *session);
+enum dlep_status dlep_base_print_status(struct dlep_session *session);
+void dlep_base_print_peer_type(struct dlep_session *session);
+int dlep_base_process_peer_termination(struct dlep_session *);
+int dlep_base_process_peer_termination_ack(struct dlep_session *);
+int dlep_base_process_heartbeat(struct dlep_session *);
+int dlep_base_write_mac_only(
+    struct dlep_session *session, const struct netaddr *neigh);
+
+#endif /* _DLEP_BASE_H_ */
diff --git a/src-plugins/generic/dlep/dlep_base/dlep_base_radio.c b/src-plugins/generic/dlep/dlep_base/dlep_base_radio.c
new file mode 100644 (file)
index 0000000..32628e4
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * dlep_base_radio.c
+ *
+ *  Created on: Jun 29, 2015
+ *      Author: rogge
+ */
+
+
+#include "../dlep_base/dlep_base_radio.h"
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/autobuf.h"
+#include "core/oonf_logging.h"
+
+#include "subsystems/oonf_layer2.h"
+#include "subsystems/oonf_class.h"
+
+#include "dlep/dlep_iana.h"
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_reader.h"
+#include "dlep/dlep_session.h"
+#include "dlep/dlep_writer.h"
+#include "dlep/radio/dlep_radio_interface.h"
+#include "dlep/radio/dlep_radio_session.h"
+#include "dlep/dlep_base/dlep_base.h"
+#include "dlep/dlep_base/dlep_base_radio.h"
+
+struct _mandatory_data {
+  enum oonf_layer2_neighbor_index layer2;
+  int64_t value;
+};
+
+static void _cb_init_radio(struct dlep_session *session);
+static void _cb_cleanup_radio(struct dlep_session *session);
+
+static int _radio_process_peer_discovery(struct dlep_session *);
+static int _radio_process_peer_init(struct dlep_session *);
+static int _radio_process_peer_update(struct dlep_session *);
+static int _radio_process_peer_update_ack(struct dlep_session *);
+static int _radio_process_destination_up(struct dlep_session *);
+static int _radio_process_destination_up_ack(struct dlep_session *);
+static int _radio_process_destination_down(struct dlep_session *);
+static int _radio_process_destination_down_ack(struct dlep_session *);
+static int _radio_process_destination_update(struct dlep_session *);
+static int _radio_process_link_char_request(struct dlep_session *);
+
+static int _radio_write_peer_offer(
+    struct dlep_session *session, const struct netaddr *);
+static int _radio_write_peer_init_ack(
+    struct dlep_session *session, const struct netaddr *);
+static int _radio_write_destination_mac_data(
+    struct dlep_session *session, const struct netaddr *);
+
+static void _l2_neigh_added_to_session(
+    struct dlep_session *session, struct oonf_layer2_neigh *l2neigh,
+      struct oonf_layer2_destination *l2dest, const struct netaddr *mac);
+static void _l2_neigh_added(struct oonf_layer2_neigh *l2neigh,
+      struct oonf_layer2_destination *l2dest, const struct netaddr *mac);
+
+static void _cb_l2_neigh_added(void *);
+static void _cb_l2_neigh_changed(void *);
+static void _cb_l2_neigh_removed(void *);
+
+static void _cb_l2_dst_added(void *);
+static void _cb_l2_dst_removed(void *);
+
+static void _cb_destination_timeout(struct dlep_session *,
+    struct dlep_local_neighbor *);
+
+static struct dlep_extension_implementation _radio_signals[] = {
+    {
+        .id = DLEP_PEER_DISCOVERY,
+        .process = _radio_process_peer_discovery
+    },
+    {
+        .id = DLEP_PEER_OFFER,
+        .add_tlvs = _radio_write_peer_offer,
+    },
+    {
+        .id = DLEP_PEER_INITIALIZATION,
+        .process = _radio_process_peer_init,
+    },
+    {
+        .id = DLEP_PEER_INITIALIZATION_ACK,
+        .add_tlvs = _radio_write_peer_init_ack,
+    },
+    {
+        .id = DLEP_PEER_UPDATE,
+        .process = _radio_process_peer_update,
+    },
+    {
+        .id = DLEP_PEER_UPDATE_ACK,
+        .process = _radio_process_peer_update_ack,
+    },
+    {
+        .id = DLEP_PEER_TERMINATION,
+        .process = dlep_base_process_peer_termination,
+    },
+    {
+        .id = DLEP_PEER_TERMINATION_ACK,
+        .process = dlep_base_process_peer_termination_ack,
+    },
+    {
+        .id = DLEP_DESTINATION_UP,
+        .process = _radio_process_destination_up,
+        .add_tlvs = _radio_write_destination_mac_data,
+    },
+    {
+        .id = DLEP_DESTINATION_UP_ACK,
+        .process = _radio_process_destination_up_ack,
+        .add_tlvs = dlep_base_write_mac_only,
+    },
+    {
+        .id = DLEP_DESTINATION_DOWN,
+        .process = _radio_process_destination_down,
+        .add_tlvs = dlep_base_write_mac_only,
+    },
+    {
+        .id = DLEP_DESTINATION_DOWN_ACK,
+        .process = _radio_process_destination_down_ack,
+        .add_tlvs = dlep_base_write_mac_only,
+    },
+    {
+        .id = DLEP_DESTINATION_UPDATE,
+        .process = _radio_process_destination_update,
+        .add_tlvs = _radio_write_destination_mac_data,
+    },
+    {
+        .id = DLEP_HEARTBEAT,
+        .process = dlep_base_process_heartbeat,
+    },
+    {
+        .id = DLEP_LINK_CHARACTERISTICS_REQUEST,
+        .process = _radio_process_link_char_request,
+    },
+};
+
+static struct _mandatory_data _mandatory_l2neigh_data[] = {
+    { .layer2 = OONF_LAYER2_NEIGH_TX_MAX_BITRATE, .value = 0 },
+    { .layer2 = OONF_LAYER2_NEIGH_RX_BITRATE, .value = 0 },
+    { .layer2 = OONF_LAYER2_NEIGH_TX_MAX_BITRATE, .value = 0 },
+    { .layer2 = OONF_LAYER2_NEIGH_RX_BITRATE, .value = 0 },
+    { .layer2 = OONF_LAYER2_NEIGH_LATENCY, .value = 1000000 },
+};
+
+static struct oonf_class_extension _layer2_neigh_listener = {
+  .ext_name = "dlep radio",
+  .class_name = LAYER2_CLASS_NEIGHBOR,
+
+  .cb_add = _cb_l2_neigh_added,
+  .cb_change = _cb_l2_neigh_changed,
+  .cb_remove = _cb_l2_neigh_removed,
+};
+
+static struct oonf_class_extension _layer2_dst_listener = {
+  .ext_name = "dlep radio",
+  .class_name = LAYER2_CLASS_DESTINATION,
+
+  .cb_add = _cb_l2_dst_added,
+  .cb_remove = _cb_l2_dst_removed,
+};
+
+static struct dlep_extension *_base;
+
+void
+dlep_base_radio_init(void) {
+  _base = dlep_base_init();
+  dlep_extension_add_processing(_base, true,
+      _radio_signals, ARRAYSIZE(_radio_signals));
+
+  oonf_class_extension_add(&_layer2_neigh_listener);
+  oonf_class_extension_add(&_layer2_dst_listener);
+
+  _base->cb_session_init_radio = _cb_init_radio;
+  _base->cb_session_cleanup_radio = _cb_cleanup_radio;
+}
+
+static void
+_cb_init_radio(struct dlep_session *session) {
+  if (session->next_signal == DLEP_PEER_INITIALIZATION) {
+    /*
+     * we are waiting for a Peer Init,
+     */
+    session->remote_heartbeat_interval = session->cfg.heartbeat_interval;
+    dlep_base_start_remote_heartbeat(session);
+  }
+
+  session->cb_destination_timeout = _cb_destination_timeout;
+}
+
+static void
+_cb_cleanup_radio(struct dlep_session *session) {
+  dlep_base_stop_timers(session);
+}
+
+static int
+_radio_process_peer_discovery(struct dlep_session *session) {
+  if (session->next_signal != DLEP_PEER_DISCOVERY) {
+    /* ignore unless we are in discovery mode */
+    return 0;
+  }
+  return dlep_session_generate_signal(session, DLEP_PEER_OFFER, NULL);
+}
+
+static int
+_radio_process_peer_init(struct dlep_session *session) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_destination *l2dest;
+  struct dlep_parser_value *value;
+  const uint8_t *ptr;
+
+  if (session->next_signal != DLEP_PEER_INITIALIZATION) {
+    /* ignore unless we are in initialization mode */
+    return 0;
+  }
+
+  /* mandatory heartbeat tlv */
+  if (dlep_reader_heartbeat_tlv(
+      &session->remote_heartbeat_interval, session, NULL)) {
+    OONF_WARN(session->log_source, "no heartbeat tlv, should not happen!");
+    return -1;
+  }
+
+  OONF_DEBUG(session->log_source, "Remote heartbeat interval %"PRIu64,
+      session->remote_heartbeat_interval);
+
+  dlep_base_start_local_heartbeat(session);
+  dlep_base_start_remote_heartbeat(session);
+
+  /* optional peer type tlv */
+  dlep_base_print_peer_type(session);
+
+  /* optional extension supported tlv */
+  value = dlep_session_get_tlv_value(session, DLEP_EXTENSIONS_SUPPORTED_TLV);
+  if (value) {
+    ptr = dlep_session_get_tlv_binary(session, value);
+    if (dlep_session_update_extensions(session, ptr, value->length/2)) {
+      return -1;
+    }
+  }
+
+  if (dlep_session_generate_signal(
+      session, DLEP_PEER_INITIALIZATION_ACK, NULL)) {
+    return -1;
+  }
+
+  /* trigger DESTINATION UP for all existing elements in l2 db */
+  l2net = oonf_layer2_net_get(session->l2_listener.name);
+  if (l2net) {
+    avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
+      if (session->cfg.send_neighbors) {
+        _l2_neigh_added_to_session(session, l2neigh, NULL, &l2neigh->addr);
+      }
+
+      if (session->cfg.send_proxied) {
+        avl_for_each_element(&l2neigh->destinations, l2dest, _node) {
+          _l2_neigh_added_to_session(
+              session, l2neigh, l2dest, &l2dest->destination);
+        }
+      }
+    }
+  }
+
+  session->next_signal = DLEP_ALL_SIGNALS;
+
+  return 0;
+}
+
+static int
+_radio_process_peer_update(struct dlep_session *session) {
+  /* we don't support IP address exchange with the router at the moment */
+  return dlep_session_generate_signal(session, DLEP_PEER_UPDATE_ACK, NULL);
+}
+
+static int
+_radio_process_peer_update_ack(struct dlep_session *session) {
+  dlep_base_print_status(session);
+  return 0;
+}
+
+static int
+_radio_process_destination_up(struct dlep_session *session) {
+  struct netaddr mac;
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    return -1;
+  }
+
+  /* we don't support IP address exchange with the router at the moment */
+  return dlep_session_generate_signal(
+      session, DLEP_DESTINATION_UP_ACK, &mac);
+}
+
+static int
+_radio_process_destination_up_ack(struct dlep_session *session) {
+  struct dlep_local_neighbor *local;
+  struct netaddr mac;
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    return -1;
+  }
+
+  if (dlep_base_print_status(session) == DLEP_STATUS_OKAY) {
+    local = dlep_session_get_local_neighbor(session, &mac);
+    if (local->state == DLEP_NEIGHBOR_UP_SENT) {
+      local->state = DLEP_NEIGHBOR_UP_ACKED;
+      oonf_timer_stop(&local->_ack_timeout);
+
+      if (local->changed) {
+        dlep_session_generate_signal(session,
+            DLEP_DESTINATION_UPDATE, &mac);
+        local->changed = false;
+      }
+    }
+  }
+  return 0;
+}
+
+static int
+_radio_process_destination_down(struct dlep_session *session) {
+  struct netaddr mac;
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    return -1;
+  }
+
+  /* we don't support IP address exchange with the router at the moment */
+  return dlep_session_generate_signal(
+      session, DLEP_DESTINATION_DOWN_ACK, &mac);
+}
+
+static int
+_radio_process_destination_down_ack(struct dlep_session *session) {
+  struct dlep_local_neighbor *local;
+  struct netaddr mac;
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    return -1;
+  }
+
+  if (dlep_base_print_status(session) == DLEP_STATUS_OKAY) {
+    local = dlep_session_get_local_neighbor(session, &mac);
+    if (local->state == DLEP_NEIGHBOR_DOWN_SENT) {
+      dlep_session_remove_local_neighbor(session, local);
+    }
+  }
+  return 0;
+}
+
+static int
+_radio_process_destination_update(
+    struct dlep_session *session __attribute__((unused))) {
+  return 0;
+}
+
+static int
+_radio_process_link_char_request(
+    struct dlep_session *session __attribute__((unused))) {
+  return 0;
+}
+
+static int
+_radio_write_peer_offer(struct dlep_session *session,
+    const struct netaddr *addr __attribute__((unused))) {
+  struct dlep_radio_if *radio_if;
+  struct netaddr local_addr;
+
+  radio_if = dlep_radio_get_by_layer2_if(
+      session->l2_listener.interface->data.name);
+  if (!radio_if || &radio_if->interf.session != session) {
+    /* unknown type of session, ignore */
+    return 0;
+  }
+
+  netaddr_from_socket(&local_addr, &radio_if->tcp.socket_v4.local_socket);
+  if (netaddr_get_address_family(&local_addr) == AF_INET) {
+    dlep_writer_add_ipv4_conpoint_tlv(&session->writer,
+        &local_addr, radio_if->tcp_config.port);
+  }
+
+  netaddr_from_socket(&local_addr, &radio_if->tcp.socket_v6.local_socket);
+  if (netaddr_get_address_family(&local_addr) == AF_INET6) {
+    dlep_writer_add_ipv6_conpoint_tlv(&session->writer,
+        &local_addr, radio_if->tcp_config.port);
+  }
+  return 0;
+}
+
+static int
+_radio_write_peer_init_ack(struct dlep_session *session,
+    const struct netaddr *addr __attribute__((unused))) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_data *l2data;
+  const uint16_t *ext_ids;
+  uint16_t ext_count;
+  size_t i;
+
+  /* first make sure defaults are set correctly */
+  l2net = oonf_layer2_net_add(session->l2_listener.name);
+  if (!l2net) {
+    return -1;
+  }
+
+  for (i=0; i<ARRAYSIZE(_mandatory_l2neigh_data); i++) {
+    l2data = &l2net->neighdata[_mandatory_l2neigh_data[i].layer2];
+
+    if (!oonf_layer2_has_value(l2data)) {
+      oonf_layer2_set_value(l2data, session->l2_origin,
+          _mandatory_l2neigh_data[i].value);
+    }
+  }
+
+  /* write heartbeat interval */
+  dlep_writer_add_heartbeat_tlv(&session->writer,
+      session->remote_heartbeat_interval);
+
+  /* write default metric values */
+  if (dlep_writer_map_l2neigh_data(&session->writer, _base,
+      l2net->neighdata)) {
+    return -1;
+  }
+
+  /* write supported extensions */
+  ext_ids = dlep_extension_get_ids(&ext_count);
+  if (ext_count) {
+    dlep_writer_add_supported_extensions(
+        &session->writer, ext_ids, ext_count);
+  }
+
+  if (session->cfg.peer_type) {
+    dlep_writer_add_peer_type_tlv(
+        &session->writer, session->cfg.peer_type);
+  }
+
+  return 0;
+}
+
+static int
+_radio_write_destination_mac_data(
+    struct dlep_session *session, const struct netaddr *neigh) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+
+  l2net = oonf_layer2_net_get(session->l2_listener.name);
+  if (!l2net) {
+    return -1;
+  }
+
+  l2neigh = oonf_layer2_neigh_get(l2net, neigh);
+  if (!l2neigh) {
+    return -1;
+  }
+
+  if (dlep_writer_add_mac_tlv(&session->writer, neigh)) {
+    return -1;
+  }
+
+  if (dlep_writer_map_l2neigh_data(&session->writer, _base,
+      l2neigh->data)) {
+    return -1;
+  }
+  return 0;
+}
+
+static void
+_l2_neigh_added_to_session(struct dlep_session *session,
+    struct oonf_layer2_neigh *l2neigh,
+      struct oonf_layer2_destination *l2dest, const struct netaddr *mac) {
+  struct dlep_local_neighbor *local;
+
+  local = dlep_session_add_local_neighbor(session, mac);
+
+  if (local) {
+    if (l2dest) {
+      memcpy(&local->neigh_addr, &l2neigh->addr, sizeof(local->neigh_addr));
+    }
+    else {
+      netaddr_invalidate(&local->neigh_addr);
+    }
+
+    dlep_session_generate_signal(session, DLEP_DESTINATION_UP, mac);
+    local->state = DLEP_NEIGHBOR_UP_SENT;
+    oonf_timer_set(&local->_ack_timeout,
+        session->cfg.heartbeat_interval * 2);
+  }
+}
+
+static void
+_l2_neigh_added(struct oonf_layer2_neigh *l2neigh,
+    struct oonf_layer2_destination *l2dest, const struct netaddr *mac) {
+  struct dlep_radio_if *radio_if;
+  struct dlep_radio_session *radio_session;
+
+  radio_if = dlep_radio_get_by_layer2_if(l2neigh->network->name);
+  if (!radio_if) {
+    return;
+  }
+
+  avl_for_each_element(&radio_if->interf.session_tree, radio_session, _node) {
+    if (l2dest && !radio_session->session.cfg.send_proxied) {
+      continue;
+    }
+    if (!l2dest && !radio_session->session.cfg.send_neighbors) {
+      continue;
+    }
+    _l2_neigh_added_to_session(&radio_if->interf.session, l2neigh, l2dest, mac);
+  }
+}
+
+static void
+_l2_neigh_changed(struct oonf_layer2_neigh *l2neigh,
+    struct oonf_layer2_destination *l2dest, const struct netaddr *mac) {
+  struct dlep_radio_if *radio_if;
+  struct dlep_radio_session *radio_session;
+  struct dlep_local_neighbor *local;
+
+  radio_if = dlep_radio_get_by_layer2_if(l2neigh->network->name);
+  if (!radio_if) {
+    return;
+  }
+
+  avl_for_each_element(&radio_if->interf.session_tree, radio_session, _node) {
+    if (l2dest && !radio_session->session.cfg.send_proxied) {
+      continue;
+    }
+    if (!l2dest && !radio_session->session.cfg.send_neighbors) {
+      continue;
+    }
+
+    local = dlep_session_add_local_neighbor(
+        &radio_session->session, mac);
+
+    if (local) {
+      if (l2dest) {
+        memcpy(&local->neigh_addr, &l2neigh->addr, sizeof(local->neigh_addr));
+      }
+      else {
+        netaddr_invalidate(&local->neigh_addr);
+      }
+
+      switch (local->state) {
+        case DLEP_NEIGHBOR_UP_SENT:
+          local->changed = true;
+          break;
+        case DLEP_NEIGHBOR_UP_ACKED:
+          dlep_session_generate_signal(&radio_session->session,
+              DLEP_DESTINATION_UPDATE, mac);
+          local->changed = false;
+          break;
+        case DLEP_NEIGHBOR_IDLE:
+        case DLEP_NEIGHBOR_DOWN_SENT:
+        case DLEP_NEIGHBOR_DOWN_ACKED:
+          dlep_session_generate_signal(&radio_session->session,
+              DLEP_DESTINATION_UP, mac);
+          local->state = DLEP_NEIGHBOR_UP_SENT;
+          local->changed = false;
+          oonf_timer_set(&local->_ack_timeout,
+              radio_session->session.cfg.heartbeat_interval * 2);
+          break;
+        default:
+          break;
+      }
+    }
+  }
+}
+
+static void
+_l2_neigh_removed(struct oonf_layer2_neigh *l2neigh,
+    struct oonf_layer2_destination *l2dest, const struct netaddr *mac) {
+  struct dlep_radio_if *radio_if;
+  struct dlep_radio_session *radio_session;
+  struct dlep_local_neighbor *local;
+
+  radio_if = dlep_radio_get_by_layer2_if(l2neigh->network->name);
+  if (!radio_if) {
+    return;
+  }
+
+  avl_for_each_element(&radio_if->interf.session_tree, radio_session, _node) {
+    if (l2dest && !radio_session->session.cfg.send_proxied) {
+      continue;
+    }
+    if (!l2dest && !radio_session->session.cfg.send_neighbors) {
+      continue;
+    }
+
+    local = dlep_session_get_local_neighbor(
+        &radio_session->session, mac);
+    if (!local) {
+      continue;
+    }
+
+    if ((l2dest && netaddr_cmp(&l2neigh->addr, &local->neigh_addr) == 0)
+        || (!l2dest && netaddr_is_unspec(&local->neigh_addr))) {
+      dlep_session_generate_signal(&radio_session->session,
+          DLEP_DESTINATION_DOWN, mac);
+      local->state = DLEP_NEIGHBOR_DOWN_SENT;
+      oonf_timer_set(&local->_ack_timeout,
+          radio_session->session.cfg.heartbeat_interval * 2);
+    }
+  }
+
+}
+
+static void
+_cb_l2_neigh_added(void *ptr) {
+  struct oonf_layer2_neigh *l2neigh = ptr;
+
+  _l2_neigh_added(l2neigh, NULL, &l2neigh->addr);
+}
+
+static void
+_cb_l2_neigh_changed(void *ptr) {
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_destination *l2dst;
+
+  l2neigh = ptr;
+  _l2_neigh_changed(l2neigh, NULL, &l2neigh->addr);
+
+  avl_for_each_element(&l2neigh->destinations, l2dst, _node) {
+    _l2_neigh_changed(l2neigh, l2dst, &l2dst->destination);
+  }
+}
+
+static void
+_cb_l2_neigh_removed(void *ptr) {
+  struct oonf_layer2_neigh *l2neigh = ptr;
+
+  _l2_neigh_removed(l2neigh, NULL, &l2neigh->addr);
+}
+
+static void
+_cb_l2_dst_added(void *ptr) {
+  struct oonf_layer2_destination *l2dst = ptr;
+
+  _l2_neigh_added(l2dst->neighbor, NULL, &l2dst->destination);
+}
+
+static void
+_cb_l2_dst_removed(void *ptr) {
+  struct oonf_layer2_destination *l2dst = ptr;
+
+  _l2_neigh_removed(l2dst->neighbor, NULL, &l2dst->destination);
+}
+
+static void
+_cb_destination_timeout(struct dlep_session *session,
+    struct dlep_local_neighbor *local) {
+  dlep_session_remove_local_neighbor(session, local);
+}
diff --git a/src-plugins/generic/dlep/dlep_base/dlep_base_radio.h b/src-plugins/generic/dlep/dlep_base/dlep_base_radio.h
new file mode 100644 (file)
index 0000000..cd44614
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * dlep_base_radio.h
+ *
+ *  Created on: Jun 29, 2015
+ *      Author: rogge
+ */
+
+#ifndef _DLEP_BASE_RADIO_H_
+#define _DLEP_BASE_RADIO_H_
+
+void dlep_base_radio_init(void);
+
+#endif /* _DLEP_BASE_RADIO_H_ */
diff --git a/src-plugins/generic/dlep/dlep_base/dlep_base_router.c b/src-plugins/generic/dlep/dlep_base/dlep_base_router.c
new file mode 100644 (file)
index 0000000..c149521
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * dlep_base_radio.c
+ *
+ *  Created on: Jun 29, 2015
+ *      Author: rogge
+ */
+
+
+#include "../dlep_base/dlep_base_router.h"
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/autobuf.h"
+#include "core/oonf_logging.h"
+
+#include "dlep/dlep_iana.h"
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_reader.h"
+#include "dlep/dlep_writer.h"
+#include "dlep/router/dlep_router_interface.h"
+#include "dlep/router/dlep_router_session.h"
+#include "dlep/dlep_base/dlep_base.h"
+#include "dlep/dlep_base/dlep_base_router.h"
+
+static void _cb_init_router(struct dlep_session *);
+static void _cb_apply_router(struct dlep_session *);
+static void _cb_cleanup_router(struct dlep_session *);
+static void _cb_peer_create_discovery(void *);
+
+static int _router_process_peer_offer(struct dlep_session *);
+static int _router_process_peer_init_ack(struct dlep_session *);
+static int _router_process_peer_update(struct dlep_session *);
+static int _router_process_peer_update_ack(struct dlep_session *);
+static int _router_process_destination_up(struct dlep_session *);
+static int _router_process_destination_up_ack(struct dlep_session *);
+static int _router_process_destination_down(struct dlep_session *);
+static int _router_process_destination_down_ack(struct dlep_session *);
+static int _router_process_destination_update(struct dlep_session *);
+static int _router_process_link_char_ack(struct dlep_session *);
+
+static int _router_write_peer_discovery(
+    struct dlep_session *session, const struct netaddr *);
+static int _router_write_peer_init(
+    struct dlep_session *session, const struct netaddr *);
+
+static struct dlep_extension_implementation _router_signals[] = {
+    {
+        .id = DLEP_PEER_DISCOVERY,
+        .add_tlvs = _router_write_peer_discovery,
+    },
+    {
+        .id = DLEP_PEER_OFFER,
+        .process = _router_process_peer_offer,
+    },
+    {
+        .id = DLEP_PEER_INITIALIZATION,
+        .add_tlvs = _router_write_peer_init,
+    },
+    {
+        .id = DLEP_PEER_INITIALIZATION_ACK,
+        .process = _router_process_peer_init_ack,
+    },
+    {
+        .id = DLEP_PEER_UPDATE,
+        .process = _router_process_peer_update,
+    },
+    {
+        .id = DLEP_PEER_UPDATE_ACK,
+        .process = _router_process_peer_update_ack,
+    },
+    {
+        .id = DLEP_PEER_TERMINATION,
+        .process = dlep_base_process_peer_termination,
+    },
+    {
+        .id = DLEP_PEER_TERMINATION_ACK,
+        .process = dlep_base_process_peer_termination_ack,
+    },
+    {
+        .id = DLEP_DESTINATION_UP,
+        .process = _router_process_destination_up,
+    },
+    {
+        .id = DLEP_DESTINATION_UP_ACK,
+        .process = _router_process_destination_up_ack,
+        .add_tlvs = dlep_base_write_mac_only,
+    },
+    {
+        .id = DLEP_DESTINATION_DOWN,
+        .process = _router_process_destination_down,
+    },
+    {
+        .id = DLEP_DESTINATION_DOWN_ACK,
+        .process = _router_process_destination_down_ack,
+        .add_tlvs = dlep_base_write_mac_only,
+    },
+    {
+        .id = DLEP_DESTINATION_UPDATE,
+        .process = _router_process_destination_update,
+    },
+    {
+        .id = DLEP_HEARTBEAT,
+        .process = dlep_base_process_heartbeat,
+    },
+    {
+        .id = DLEP_LINK_CHARACTERISTICS_ACK,
+        .process = _router_process_link_char_ack,
+    },
+};
+
+static struct oonf_timer_class _peer_discovery_class = {
+    .name = "dlep peer discovery",
+    .callback = _cb_peer_create_discovery,
+    .periodic = true,
+};
+static struct dlep_extension *_base;
+
+void
+dlep_base_router_init(void) {
+  _base = dlep_base_init();
+  dlep_extension_add_processing(_base, false,
+      _router_signals, ARRAYSIZE(_router_signals));
+
+  oonf_timer_add(&_peer_discovery_class);
+
+  _base->cb_session_init_router = _cb_init_router;
+  _base->cb_session_apply_router = _cb_apply_router;
+  _base->cb_session_cleanup_router = _cb_cleanup_router;
+}
+
+static void
+_cb_init_router(struct dlep_session *session) {
+  if (session->next_signal == DLEP_PEER_INITIALIZATION_ACK) {
+    /*
+     * we are waiting for a Peer Init Ack,
+     * so we need to send a Peer Init
+     */
+    dlep_session_generate_signal(session, DLEP_PEER_INITIALIZATION, NULL);
+    session->cb_send_buffer(session, 0);
+
+    session->remote_heartbeat_interval = session->cfg.heartbeat_interval;
+    dlep_base_start_remote_heartbeat(session);
+  }
+}
+
+static void
+_cb_apply_router(struct dlep_session *session) {
+  OONF_DEBUG(session->log_source, "Initialize base router session");
+  if (session->next_signal == DLEP_PEER_OFFER) {
+    /*
+     * we are waiting for a Peer Offer,
+     * so we need to send Peer Discovery messages
+     */
+    session->local_event_timer.class = &_peer_discovery_class;
+    session->local_event_timer.cb_context = session;
+
+    OONF_DEBUG(session->log_source, "Activate discovery with interval %"
+        PRIu64, session->cfg.discovery_interval);
+
+    /* use the "local event" for the discovery timer */
+    oonf_timer_start(&session->local_event_timer,
+        session->cfg.discovery_interval);
+  }
+}
+
+static void
+_cb_cleanup_router(struct dlep_session *session) {
+  struct oonf_layer2_net *l2net;
+
+  l2net = oonf_layer2_net_get(session->l2_listener.name);
+  if (l2net) {
+    oonf_layer2_net_remove(l2net, session->l2_origin);
+  }
+
+  dlep_base_stop_timers(session);
+}
+
+static void
+_cb_peer_create_discovery(void *ptr) {
+  struct dlep_session *session = ptr;
+
+  OONF_DEBUG(session->log_source, "Generate peer discovery");
+
+  dlep_session_generate_signal(session, DLEP_PEER_DISCOVERY, NULL);
+  session->cb_send_buffer(session, AF_INET);
+
+  dlep_session_generate_signal(session, DLEP_PEER_DISCOVERY, NULL);
+  session->cb_send_buffer(session, AF_INET6);
+}
+
+static int
+_router_process_peer_offer(struct dlep_session *session) {
+  struct dlep_router_if *router_if;
+  union netaddr_socket local, remote;
+  struct dlep_parser_value *value;
+  const struct netaddr *result = NULL;
+  struct netaddr addr;
+  uint16_t port;
+  struct os_interface_data *ifdata;
+
+  if (session->next_signal != DLEP_PEER_OFFER) {
+    /* ignore unless we are in discovery mode */
+    return 0;
+  }
+
+  /* optional peer type tlv */
+  dlep_base_print_peer_type(session);
+
+  /* we are looking for a good address to respond to */
+  result = NULL;
+
+  /* remember interface data */
+  ifdata = &session->l2_listener.interface->data;
+
+  /* IPv6 offer */
+  value = dlep_session_get_tlv_value(session, DLEP_IPV6_CONPOINT_TLV);
+  while (value) {
+    if (dlep_reader_ipv6_conpoint_tlv(&addr, &port, session, value)) {
+      return -1;
+    }
+
+    if (netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, &addr)
+        || result == NULL) {
+      result = oonf_interface_get_prefix_from_dst(&addr, ifdata);
+      if (result) {
+        netaddr_socket_init(&remote, &addr, port, ifdata->index);
+      }
+    }
+    value = dlep_session_get_next_tlv_value(session, value);
+  }
+
+  /* IPv4 offer */
+  value = dlep_session_get_tlv_value(session, DLEP_IPV4_CONPOINT_TLV);
+  while (value && !result) {
+    if (dlep_reader_ipv4_conpoint_tlv(&addr, &port, session, value)) {
+      return -1;
+    }
+
+    result = oonf_interface_get_prefix_from_dst(&addr, ifdata);
+    if (result) {
+      netaddr_socket_init(&remote, &addr, port, ifdata->index);
+    }
+    value = dlep_session_get_next_tlv_value(session, value);
+  }
+
+  /* remote address of incoming session */
+  if (!result) {
+    netaddr_from_socket(&addr, &session->remote_socket);
+    result = oonf_interface_get_prefix_from_dst(&addr, ifdata);
+    if (!result) {
+      /* no possible way to communicate */
+      return -1;
+    }
+    netaddr_socket_init(&remote, &addr, port, ifdata->index);
+  }
+
+  /* initialize session */
+  netaddr_socket_init(&local, result, 0, ifdata->index);
+
+  router_if = dlep_router_get_by_layer2_if(ifdata->name);
+  if (router_if && &router_if->interf.session == session) {
+    dlep_router_add_session(router_if, &local, &remote);
+    return 0;
+  }
+  /* ignore incoming offer, something is wrong */
+  return -1;
+}
+
+static int
+_router_process_peer_init_ack(struct dlep_session *session) {
+  if (session->next_signal != DLEP_PEER_INITIALIZATION_ACK) {
+    /* ignore unless we are in initialization mode */
+    return 0;
+  }
+
+  /* mandatory heartbeat tlv */
+  if (dlep_reader_heartbeat_tlv(
+      &session->remote_heartbeat_interval, session, NULL)) {
+    OONF_WARN(session->log_source, "no heartbeat tlv, should not happen!");
+    return -1;
+  }
+
+  OONF_DEBUG(session->log_source, "Remote heartbeat interval %"PRIu64,
+      session->remote_heartbeat_interval);
+
+  dlep_base_start_local_heartbeat(session);
+  dlep_base_start_remote_heartbeat(session);
+
+  dlep_base_print_status(session);
+
+  session->next_signal = DLEP_ALL_SIGNALS;
+
+  return 0;
+}
+
+static int
+_router_process_peer_update(struct dlep_session *session) {
+  struct oonf_layer2_net *l2net;
+
+  l2net = oonf_layer2_net_add(session->l2_listener.name);
+  if (!l2net) {
+    return -1;
+  }
+  if (dlep_reader_map_l2neigh_data(l2net->neighdata, session, _base)) {
+    return -1;
+  }
+
+  // we don't support IP address exchange at the moment
+  return 0;
+}
+
+static int
+_router_process_peer_update_ack(struct dlep_session *session) {
+  dlep_base_print_status(session);
+  return 0;
+}
+
+static int
+_router_process_destination_up(struct dlep_session *session) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+  struct netaddr mac;
+
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    OONF_DEBUG(session->log_source, "mac tlv missing");
+    return -1;
+  }
+
+  l2net = oonf_layer2_net_add(session->l2_listener.name);
+  if (!l2net) {
+    return dlep_session_generate_signal_status(
+        session, DLEP_DESTINATION_UP_ACK, &mac,
+        DLEP_STATUS_REQUEST_DENIED, "Not enough memory");
+  }
+  l2neigh = oonf_layer2_neigh_add(l2net, &mac);
+  if (!l2neigh) {
+    return dlep_session_generate_signal_status(
+        session, DLEP_DESTINATION_UP_ACK, &mac,
+        DLEP_STATUS_REQUEST_DENIED, "Not enough memory");
+  }
+
+  if (dlep_reader_map_l2neigh_data(l2neigh->data, session, _base)) {
+    OONF_DEBUG(session->log_source, "tlv mapping failed");
+    return -1;
+  }
+
+  return dlep_session_generate_signal(
+      session, DLEP_DESTINATION_UP_ACK, &mac);
+}
+
+static int
+_router_process_destination_up_ack(struct dlep_session *session) {
+  dlep_base_print_status(session);
+  return 0;
+}
+
+static int
+_router_process_destination_down(struct dlep_session *session) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+  struct netaddr mac;
+
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    return -1;
+  }
+
+  l2net = oonf_layer2_net_get(session->l2_listener.name);
+  if (!l2net) {
+    return 0;
+  }
+
+  l2neigh = oonf_layer2_neigh_get(l2net, &mac);
+  if (!l2neigh) {
+    return 0;
+  }
+
+  /* remove layer2 neighbor */
+  oonf_layer2_neigh_remove(l2neigh, session->l2_origin);
+
+  return dlep_session_generate_signal(
+      session, DLEP_DESTINATION_UP_ACK, &mac);
+}
+
+static int
+_router_process_destination_down_ack(struct dlep_session *session) {
+  dlep_base_print_status(session);
+  return 0;
+}
+
+static int
+_router_process_destination_update(struct dlep_session *session) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+  struct netaddr mac;
+
+  if (dlep_reader_mac_tlv(&mac, session, NULL)) {
+    return -1;
+  }
+
+  l2net = oonf_layer2_net_get(session->l2_listener.name);
+  if (!l2net) {
+    return 0;
+  }
+
+  l2neigh = oonf_layer2_neigh_get(l2net, &mac);
+  if (!l2neigh) {
+    /* we did not get the destination up signal */
+    return 0;
+  }
+
+  if (dlep_reader_map_l2neigh_data(l2neigh->data, session, _base)) {
+    return -1;
+  }
+
+  return 0;
+}
+
+static int
+_router_process_link_char_ack(struct dlep_session *session) {
+  dlep_base_print_status(session);
+  return 0;
+}
+
+static int
+_router_write_peer_discovery(struct dlep_session *session,
+    const struct netaddr *addr __attribute__((unused))) {
+  if (session->next_signal != DLEP_PEER_OFFER) {
+    return -1;
+  }
+  return 0;
+}
+
+static int
+_router_write_peer_init(struct dlep_session *session,
+    const struct netaddr *addr __attribute__((unused))) {
+  const uint16_t *ext_ids;
+  uint16_t ext_count;
+
+  /* write supported extensions */
+  ext_ids = dlep_extension_get_ids(&ext_count);
+  if (ext_count) {
+    dlep_writer_add_supported_extensions(
+        &session->writer, ext_ids, ext_count);
+  }
+
+  dlep_writer_add_heartbeat_tlv(&session->writer,
+      session->cfg.heartbeat_interval);
+
+  if (session->cfg.peer_type) {
+    dlep_writer_add_peer_type_tlv(
+        &session->writer, session->cfg.peer_type);
+  }
+
+  return 0;
+}
diff --git a/src-plugins/generic/dlep/dlep_base/dlep_base_router.h b/src-plugins/generic/dlep/dlep_base/dlep_base_router.h
new file mode 100644 (file)
index 0000000..88b5291
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * dlep_base_radio.h
+ *
+ *  Created on: Jun 29, 2015
+ *      Author: rogge
+ */
+
+#ifndef _DLEP_BASE_ROUTER_H_
+#define _DLEP_BASE_ROUTER_H_
+
+#include "core/oonf_logging.h"
+
+void dlep_base_router_init(void);
+
+#endif /* _DLEP_BASE_ROUTER_H_ */
diff --git a/src-plugins/generic/dlep/dlep_extension.c b/src-plugins/generic/dlep/dlep_extension.c
new file mode 100644 (file)
index 0000000..3bbff4a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * dlep_extension.c
+ *
+ *  Created on: Jun 25, 2015
+ *      Author: rogge
+ */
+
+#include <stdlib.h>
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+
+#include "dlep/dlep_extension.h"
+
+static struct avl_tree _extension_tree;
+
+static uint16_t *_id_array = NULL;
+static uint16_t _id_array_length = 0;
+
+void
+dlep_extension_init(void) {
+  avl_init(&_extension_tree, avl_comp_int32, false);
+}
+
+void
+dlep_extension_add(struct dlep_extension *ext) {
+  uint16_t *ptr;
+
+  if (avl_is_node_added(&ext->_node)) {
+    return;
+  }
+
+  ptr = realloc(_id_array, sizeof(uint16_t) * _extension_tree.count);
+  if (!ptr) {
+    return;
+  }
+
+  /* add to tree */
+  ext->_node.key = &ext->id;
+  avl_insert(&_extension_tree, &ext->_node);
+
+  /* refresh id array */
+  _id_array_length = 0;
+  _id_array = ptr;
+
+  avl_for_each_element(&_extension_tree, ext, _node) {
+    if (ext->id >= 0 && ext->id <= 0xffff) {
+      ptr[_id_array_length] = ext->id;
+      _id_array_length++;
+    }
+  }
+}
+
+struct avl_tree *
+dlep_extension_get_tree(void) {
+  return &_extension_tree;
+}
+
+void
+dlep_extension_add_processing(struct dlep_extension *ext, bool radio,
+    struct dlep_extension_implementation *processing, size_t proc_count) {
+  size_t i,j;
+
+  for (j=0; j<proc_count; j++) {
+    for (i=0; i<ext->signal_count; i++) {
+      if (ext->signals[i].id == processing[j].id) {
+        if (radio) {
+          ext->signals[i].process_radio = processing[j].process;
+          ext->signals[i].add_radio_tlvs = processing[j].add_tlvs;
+        }
+        else {
+          ext->signals[i].process_router = processing[j].process;
+          ext->signals[i].add_router_tlvs = processing[j].add_tlvs;
+        }
+        break;
+      }
+    }
+  }
+}
+
+const uint16_t *
+dlep_extension_get_ids(uint16_t *length) {
+  *length = _id_array_length;
+  return _id_array;
+}
diff --git a/src-plugins/generic/dlep/dlep_extension.h b/src-plugins/generic/dlep/dlep_extension.h
new file mode 100644 (file)
index 0000000..3a33bdd
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * dlep_extension.h
+ *
+ *  Created on: Jun 25, 2015
+ *      Author: rogge
+ */
+
+#ifndef _DLEP_EXTENSION_H_
+#define _DLEP_EXTENSION_H_
+
+struct dlep_extension;
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/autobuf.h"
+
+#include "subsystems/oonf_layer2.h"
+
+#include "dlep/dlep_session.h"
+
+enum {
+  DLEP_EXTENSION_BASE      = -1,
+};
+
+struct dlep_extension_signal {
+    /* signal id */
+    uint16_t id;
+
+    /* array of supported tlv ids */
+    const uint16_t *supported_tlvs;
+    size_t supported_tlv_count;
+
+    /* array of mandatory tlv ids */
+    const uint16_t *mandatory_tlvs;
+    size_t mandatory_tlv_count;
+
+    /* array of tlvs that are allowed multiple times */
+    const uint16_t *duplicate_tlvs;
+    size_t duplicate_tlv_count;
+
+    enum dlep_parser_error (*process_radio)(struct dlep_session *session);
+    enum dlep_parser_error (*process_router)(struct dlep_session *session);
+    int (*add_radio_tlvs)(struct dlep_session *session, const struct netaddr *);
+    int (*add_router_tlvs)(struct dlep_session *session, const struct netaddr *);
+};
+
+struct dlep_extension_tlv {
+    uint16_t id;
+    uint16_t length_min;
+    uint16_t length_max;
+};
+
+struct dlep_extension_implementation {
+    uint16_t id;
+
+    enum dlep_parser_error (*process)(struct dlep_session *session);
+    int (*add_tlvs)(struct dlep_session *session, const struct netaddr *);
+};
+
+struct dlep_neighbor_mapping {
+    uint16_t dlep;
+    uint16_t length;
+
+    enum oonf_layer2_neighbor_index layer2;
+
+    int (*from_tlv)(struct oonf_layer2_data *, struct dlep_session *,
+        uint16_t tlv);
+    int (*to_tlv)(struct dlep_writer *, struct oonf_layer2_data *,
+        uint16_t tlv, uint16_t length);
+};
+
+struct dlep_network_mapping {
+    uint16_t dlep;
+    uint16_t length;
+
+    enum oonf_layer2_network_index layer2;
+
+    int (*from_tlv)(struct oonf_layer2_data *, struct dlep_session *,
+        uint16_t tlv);
+    int (*to_tlv)(struct dlep_writer *, struct oonf_layer2_data *,
+        uint16_t tlv, uint16_t length);
+};
+
+struct dlep_extension {
+    /* id of dlep extension, -1 for base protocol */
+    int id;
+
+    /* name of extension for debugging purpose */
+    const char *name;
+
+    /* array of dlep signals used by this extension */
+    struct dlep_extension_signal *signals;
+    size_t signal_count;
+
+    /* array of dlep tlvs used by this extension */
+    struct dlep_extension_tlv *tlvs;
+    size_t tlv_count;
+
+    /*
+     * array of id mappings between DLEP tlvs
+     * and oonf-layer2 neighbor data
+     */
+    struct dlep_neighbor_mapping *neigh_mapping;
+    size_t neigh_mapping_count;
+
+    /*
+     * array of id mappings between DLEP tlvs
+     * and oonf-layer2 network data
+     */
+    struct dlep_network_mapping *if_mapping;
+    size_t if_mapping_count;
+
+    /* callbacks for session creation and teardown */
+    void (*cb_session_init_radio)(struct dlep_session *);
+    void (*cb_session_init_router)(struct dlep_session *);
+    void (*cb_session_apply_radio)(struct dlep_session *);
+    void (*cb_session_apply_router)(struct dlep_session *);
+    void (*cb_session_cleanup_radio)(struct dlep_session *);
+    void (*cb_session_cleanup_router)(struct dlep_session *);
+
+    /* node for global tree of extensions */
+    struct avl_node _node;
+};
+
+EXPORT void dlep_extension_init(void);
+EXPORT void dlep_extension_add(struct dlep_extension *);
+EXPORT struct avl_tree *dlep_extension_get_tree(void);
+EXPORT void dlep_extension_add_processing(struct dlep_extension *, bool radio,
+    struct dlep_extension_implementation *proc, size_t proc_count);
+EXPORT const uint16_t *dlep_extension_get_ids(uint16_t *length);
+
+static INLINE struct dlep_extension *
+dlep_extension_get(int32_t id) {
+  struct dlep_extension *ext;
+  return avl_find_element(dlep_extension_get_tree(), &id, ext, _node);
+}
+
+#endif /* _DLEP_EXTENSION_H_ */
index 8199b43..89415b3 100644 (file)
 #define DLEP_WELL_KNOWN_MULTICAST_ADDRESS_6 "FF02::6D"
 #define DLEP_WELL_KNOWN_MULTICAST_PORT_TXT "22222"
 
-/* The well-known port for modem discovery */
+/* DLEP IANA_PORT */
 enum {
-  DLEP_WELL_KNOWN_MULTICAST_PORT = 22222,
+  DLEP_PORT = 22222,
 };
 
-enum dlep_version {
-  DLEP_VERSION_MAJOR = 0,
-  DLEP_VERSION_MINOR = 14,
-};
+#define DLEP_DRAFT_15_VERSION "DLEP"
 
 enum dlep_signals {
+  /* control numbers for session handling */
+  DLEP_KILL_SESSION                 = -2,
+  DLEP_ALL_SIGNALS                  = -1,
+
+  /* signal types */
   DLEP_PEER_DISCOVERY               =  0,
   DLEP_PEER_OFFER                   =  1,
   DLEP_PEER_INITIALIZATION          =  2,
@@ -74,37 +76,34 @@ enum dlep_signals {
   DLEP_HEARTBEAT                    = 13,
   DLEP_LINK_CHARACTERISTICS_REQUEST = 14,
   DLEP_LINK_CHARACTERISTICS_ACK     = 15,
-
-  DLEP_SIGNAL_COUNT,
 };
 
 enum dlep_tlvs {
-  DLEP_VERSION_TLV             =  0,
-  DLEP_STATUS_TLV              =  1,
-  DLEP_IPV4_CONPOINT_TLV       =  2,
-  DLEP_IPV6_CONPOINT_TLV       =  3,
-  DLEP_PEER_TYPE_TLV           =  4,
-  DLEP_HEARTBEAT_INTERVAL_TLV  =  5,
-  DLEP_EXTENSIONS_SUPPORTED    =  6,
-  DLEP_EXPERIMENTAL_DEFINITION =  7,
-  DLEP_MAC_ADDRESS_TLV         =  8,
-  DLEP_IPV4_ADDRESS_TLV        =  9,
-  DLEP_IPV6_ADDRESS_TLV        = 10,
-  DLEP_IPV4_SUBNET_TLV         = 11,
-  DLEP_IPV6_SUBNET_TLV         = 12,
-  DLEP_MDRR_TLV                = 13,
-  DLEP_MDRT_TLV                = 14,
-  DLEP_CDRR_TLV                = 15,
-  DLEP_CDRT_TLV                = 16,
-  DLEP_LATENCY_TLV             = 17,
-  DLEP_RESR_TLV                = 18,
-  DLEP_REST_TLV                = 19,
-  DLEP_RLQR_TLV                = 20,
-  DLEP_RLQT_TLV                = 21,
-  DLEP_LINK_CHAR_ACK_TIMER_TLV = 22,
-  DLEP_CREDIT_GRANT_TLV        = 23,
-  DLEP_CREDIT_WIN_STATUS_TLV   = 24,
-  DLEP_CREDIT_REQUEST_TLV      = 25,
+  DLEP_VERSION_TLV                 =  0,
+  DLEP_STATUS_TLV                  =  1,
+  DLEP_IPV4_CONPOINT_TLV           =  2,
+  DLEP_IPV6_CONPOINT_TLV           =  3,
+  DLEP_PEER_TYPE_TLV               =  4,
+  DLEP_HEARTBEAT_INTERVAL_TLV      =  5,
+  DLEP_EXTENSIONS_SUPPORTED_TLV    =  6,
+  DLEP_MAC_ADDRESS_TLV             =  7,
+  DLEP_IPV4_ADDRESS_TLV            =  8,
+  DLEP_IPV6_ADDRESS_TLV            =  9,
+  DLEP_IPV4_SUBNET_TLV             = 10,
+  DLEP_IPV6_SUBNET_TLV             = 11,
+  DLEP_MDRR_TLV                    = 12,
+  DLEP_MDRT_TLV                    = 13,
+  DLEP_CDRR_TLV                    = 14,
+  DLEP_CDRT_TLV                    = 15,
+  DLEP_LATENCY_TLV                 = 16,
+  DLEP_RESR_TLV                    = 17,
+  DLEP_REST_TLV                    = 18,
+  DLEP_RLQR_TLV                    = 19,
+  DLEP_RLQT_TLV                    = 20,
+  DLEP_LINK_CHAR_ACK_TIMER_TLV     = 21,
+  DLEP_CREDIT_GRANT_TLV            = 22,
+  DLEP_CREDIT_WIN_STATUS_TLV       = 23,
+  DLEP_CREDIT_REQUEST_TLV          = 24,
 
   /* custom additions */
   DLEP_FRAMES_R_TLV,
@@ -127,8 +126,15 @@ enum dlep_ipaddr_indicator {
 };
 
 enum dlep_status {
-  DLEP_STATUS_OKAY  = 0,
-  DLEP_STATUS_ERROR = 1,
+  DLEP_STATUS_NONE                = -1,
+  DLEP_STATUS_OKAY                = 0,
+  DLEP_STATUS_UNKNOWN_SIGNAL      = 1,
+  DLEP_STATUS_INVALID_DATA        = 2,
+  DLEP_STATUS_UNEXPECTED_SIGNAL   = 3,
+  DLEP_STATUS_REQUEST_DENIED      = 4,
+  DLEP_STATUS_TIMED_OUT           = 5,
+  DLEP_STATUS_INVALID_DESTINATION = 6,
+  DLEP_STATUS_INVALID_VERSION     = 7,
 
   DLEP_STATUS_COUNT,
 };
diff --git a/src-plugins/generic/dlep/dlep_interface.c b/src-plugins/generic/dlep/dlep_interface.c
new file mode 100644 (file)
index 0000000..c1a8881
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * dlep_interface.c
+ *
+ *  Created on: Jul 8, 2015
+ *      Author: rogge
+ */
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "subsystems/oonf_packet_socket.h"
+
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_iana.h"
+#include "dlep/dlep_session.h"
+#include "dlep/dlep_writer.h"
+#include "dlep/dlep_interface.h"
+
+static void _cb_receive_udp(struct oonf_packet_socket *,
+    union netaddr_socket *from, void *ptr, size_t length);
+static void _cb_send_multicast(struct dlep_session *session, int af_family);
+
+static const char _DLEP_VERSION[] = DLEP_DRAFT_15_VERSION;
+
+int
+dlep_if_add(struct dlep_if *interf, const char *ifname,
+    uint32_t l2_origin, enum oonf_log_source log_src, bool radio) {
+  struct dlep_extension *ext;
+
+  /* initialize key */
+  strscpy(interf->l2_ifname, ifname,
+      sizeof(interf->l2_ifname));
+  interf->_node.key = interf->l2_ifname;
+
+  if (abuf_init(&interf->udp_out)) {
+    return -1;
+  }
+
+  /* add dlep version to buffer */
+  abuf_memcpy(&interf->udp_out,
+      _DLEP_VERSION, sizeof(_DLEP_VERSION) - 1);
+
+  if (dlep_session_add(&interf->session,
+      interf->l2_ifname, l2_origin,
+      &interf->udp_out,
+      radio, log_src)) {
+    abuf_free(&interf->udp_out);
+    return -1;
+  }
+
+  /* initialize stream list */
+  avl_init(&interf->session_tree, avl_comp_netaddr_socket, false);
+
+  /* initialize discovery socket */
+  interf->udp.config.user = interf;
+  interf->udp.config.receive_data = _cb_receive_udp;
+  oonf_packet_add_managed(&interf->udp);
+
+  /* initialize session */
+  interf->session.cb_send_buffer = _cb_send_multicast;
+  interf->session.cb_end_session = NULL;
+  interf->session.next_signal =
+      radio ? DLEP_PEER_DISCOVERY : DLEP_PEER_OFFER;
+  interf->session.writer.out = &interf->udp_out;
+
+  /* inform all extension */
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (radio) {
+      if (ext->cb_session_init_radio) {
+        ext->cb_session_init_radio(&interf->session);
+      }
+    }
+    else {
+      if (ext->cb_session_init_router) {
+        ext->cb_session_init_router(&interf->session);
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * Remove dlep router interface
+ * @param interface dlep router interface
+ */
+void
+dlep_if_remove(struct dlep_if *interface) {
+  struct dlep_extension *ext;
+
+  OONF_DEBUG(interface->session.log_source,
+      "remove session %s", interface->l2_ifname);
+
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (interface->session.radio) {
+      if (ext->cb_session_cleanup_radio) {
+        ext->cb_session_cleanup_radio(&interface->session);
+      }
+    }
+    else {
+      if (ext->cb_session_cleanup_router) {
+        ext->cb_session_cleanup_router(&interface->session);
+      }
+    }
+  }
+
+  /* close UDP interface */
+  oonf_packet_remove_managed(&interface->udp, true);
+
+  /* kill dlep session */
+  dlep_session_remove(&interface->session);
+}
+/**
+ * Callback to receive UDP data through oonf_packet_managed API
+ * @param pkt
+ * @param from
+ * @param ptr
+ * @param length
+ */
+static void
+_cb_receive_udp(struct oonf_packet_socket *pkt,
+    union netaddr_socket *from, void *ptr, size_t length) {
+  struct dlep_if *interf;
+  uint8_t *buffer;
+  ssize_t processed;
+  struct netaddr_str nbuf;
+
+  interf = pkt->config.user;
+  buffer = ptr;
+
+  if (interf->session_tree.count > 0
+      && interf->single_session) {
+    /* ignore UDP traffic as long as we have a connection */
+    return;
+  }
+
+  if (length < sizeof(_DLEP_VERSION) - 1) {
+    /* ignore unknown version */
+    return;
+  }
+
+  if (memcmp(buffer, _DLEP_VERSION, sizeof(_DLEP_VERSION)-1) != 0) {
+    OONF_WARN(interf->session.log_source,
+        "Incoming UDP packet with unknown signature");
+    return;
+  }
+
+  /* advance pointer and fix length */
+  buffer += (sizeof(_DLEP_VERSION) - 1);
+  length -= (sizeof(_DLEP_VERSION) - 1);
+
+  /* copy socket information */
+  memcpy(&interf->session.remote_socket, from,
+      sizeof(interf->session.remote_socket));
+
+  processed = dlep_session_process_buffer(&interf->session, buffer, length);
+  if (processed < 0) {
+    return ;
+  }
+
+  if ((size_t)processed < length) {
+    OONF_WARN(interf->session.log_source,
+        "Received malformed or too short UDP packet from %s",
+        netaddr_socket_to_string(&nbuf, from));
+    /* incomplete or bad packet, just ignore it */
+    return;
+  }
+
+  if (abuf_getlen(interf->session.writer.out) > sizeof(_DLEP_VERSION) - 1) {
+    /* send an unicast response */
+    oonf_packet_send_managed(&interf->udp, from,
+        abuf_getptr(interf->session.writer.out),
+        abuf_getlen(interf->session.writer.out));
+    abuf_clear(interf->session.writer.out);
+
+    /* add dlep version to buffer */
+    abuf_memcpy(interf->session.writer.out,
+        _DLEP_VERSION, sizeof(_DLEP_VERSION) - 1);
+  }
+
+  netaddr_socket_invalidate(&interf->session.remote_socket);
+}
+
+static void
+_cb_send_multicast(struct dlep_session *session, int af_family) {
+  struct dlep_if *interf;
+
+  if (abuf_getlen(session->writer.out) <= sizeof(_DLEP_VERSION) - 1
+      || !netaddr_socket_is_unspec(&session->remote_socket)) {
+    return;
+  }
+
+  /* get pointer to radio interface */
+  interf = container_of(session, struct dlep_if, session);
+
+  if (interf->session_tree.count > 0
+      && interf->single_session) {
+    /* do not produce UDP traffic as long as we are connected */
+    return;
+  }
+
+  OONF_DEBUG(session->log_source, "Send multicast %" PRIu64 " bytes",
+      abuf_getlen(session->writer.out));
+
+  oonf_packet_send_managed_multicast(&interf->udp,
+      abuf_getptr(session->writer.out), abuf_getlen(session->writer.out),
+      af_family);
+
+  abuf_clear(session->writer.out);
+
+  /* add dlep version to buffer */
+  abuf_memcpy(session->writer.out, _DLEP_VERSION, sizeof(_DLEP_VERSION) - 1);
+}
diff --git a/src-plugins/generic/dlep/dlep_interface.h b/src-plugins/generic/dlep/dlep_interface.h
new file mode 100644 (file)
index 0000000..945357a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * dlep_interface.h
+ *
+ *  Created on: Jul 8, 2015
+ *      Author: rogge
+ */
+
+#ifndef DLEP_INTERFACE_H_
+#define DLEP_INTERFACE_H_
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "core/oonf_logging.h"
+#include "subsystems/oonf_packet_socket.h"
+
+struct dlep_if {
+  struct dlep_session session;
+
+  /* name of layer2 interface */
+  char l2_ifname[IF_NAMESIZE];
+
+  /* UDP socket for discovery */
+  struct oonf_packet_managed udp;
+  struct oonf_packet_managed_config udp_config;
+  struct autobuf udp_out;
+
+  /* true if radio should only accept a single session */
+  bool single_session;
+
+  /* hook into session tree, interface name is the key */
+  struct avl_node _node;
+
+  /* tree of all radio sessions */
+  struct avl_tree session_tree;
+};
+
+int dlep_if_add(struct dlep_if *interf, const char *ifname,
+    uint32_t l2_origin, enum oonf_log_source log_src, bool radio);
+void dlep_if_remove(struct dlep_if *interface);
+
+#endif /* DLEP_INTERFACE_H_ */
diff --git a/src-plugins/generic/dlep/dlep_parser.c b/src-plugins/generic/dlep/dlep_parser.c
deleted file mode 100644 (file)
index 6e5d22f..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-
-/*
- * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
- * Copyright (c) 2004-2015, 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 <arpa/inet.h>
-#include <string.h>
-
-#include "common/common_types.h"
-#include "common/bitmap256.h"
-#include "common/netaddr.h"
-
-#include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
-
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE
-#endif
-#include <endian.h> /* be64toh */
-
-
-static int _check_tlv_length(uint8_t type, uint8_t length);
-static int _check_mandatory_tlvs(struct dlep_parser_index *idx,
-    uint8_t signal);
-
-int
-dlep_parser_read(struct dlep_parser_index *idx,
-    const void *ptr, size_t total_len, uint16_t *siglen) {
-  uint8_t tlv_type, tlv_length, signal_type;
-  const uint8_t *signal;
-  uint16_t signal_length;
-  size_t pos;
-
-  if (total_len < 3) {
-    /* signal header not complete */
-    return DLEP_PARSER_INCOMPLETE_HEADER;
-  }
-
-  /* get byte-wise pointer */
-  signal = ptr;
-
-  /* get signal length */
-  memcpy(&signal_length, &signal[1], 2);
-  signal_length = ntohs(signal_length) + 3;
-  pos = 0;
-
-  if (total_len < signal_length) {
-    /* signal not complete */
-    return DLEP_PARSER_INCOMPLETE_SIGNAL;
-  }
-
-  /* get signal type */
-  signal_type = signal[0];
-
-  /* store signal length */
-  if (siglen) {
-    *siglen = signal_length;
-  }
-
-  /* prepare index */
-  memset(idx, 0, sizeof(*idx));
-
-  /* jump to first TLV */
-  pos += 3;
-
-  while (pos < signal_length) {
-    if (pos + 2 > signal_length) {
-      /* tlv header broken */
-      return DLEP_PARSER_INCOMPLETE_TLV_HEADER;
-    }
-
-    /* get tlv header */
-    tlv_type = signal[pos];
-    tlv_length = signal[pos+1];
-
-    if (pos + 2 + tlv_length > signal_length) {
-      /* tlv too long */
-      return DLEP_PARSER_INCOMPLETE_TLV;
-    }
-
-    if (_check_tlv_length(tlv_type, tlv_length)) {
-      /* length of TLV is incorrect */
-      return DLEP_PARSER_ILLEGAL_TLV_LENGTH;
-    }
-
-    /* remember index of first tlv */
-    if (tlv_type < DLEP_TLV_COUNT
-        && idx->idx[tlv_type] == 0) {
-      idx->idx[tlv_type] = pos;
-    }
-
-    /* jump to next signal */
-    pos += tlv_length + 2;
-  }
-
-  if (_check_mandatory_tlvs(idx, signal_type)) {
-    /* mandatory TLV is missing */
-    return DLEP_PARSER_MISSING_MANDATORY_TLV;
-  }
-
-  return signal[0];
-}
-
-uint16_t
-dlep_parser_get_next_tlv(const uint8_t *buffer, size_t len, size_t offset) {
-  uint8_t type;
-
-  /* remember TLV type */
-  type = buffer[offset];
-
-  /* skip current tlv */
-  offset += buffer[offset + 1];
-
-  /* look for another one of the same type */
-  while (offset < len) {
-    if (buffer[offset] == type) {
-      return offset;
-    }
-
-    offset += buffer[offset + 1];
-  }
-  return 0;
-}
-
-void
-dlep_parser_get_version(uint16_t *major, uint16_t *minor, const uint8_t *tlv) {
-  memcpy(major, &tlv[0], sizeof(*major));
-  memcpy(minor, &tlv[2], sizeof(*minor));
-
-  *major = ntohs(*major);
-  *minor = ntohs(*minor);
-}
-
-void
-dlep_parser_get_peer_type(char *string, const uint8_t *tlv) {
-  memcpy(string, &tlv[2], tlv[1]);
-  string[tlv[2]] = 0;
-}
-
-void
-dlep_parser_get_ipv4_conpoint(struct netaddr *ipv4, uint16_t *port, const uint8_t *tlv) {
-  /* length was already checked */
-  netaddr_from_binary(ipv4, &tlv[2], tlv[1]-2, AF_INET);
-
-  memcpy(port, &tlv[6], sizeof(*port));
-  *port = ntohs(*port);
-}
-
-void
-dlep_parser_get_ipv6_conpoint(struct netaddr *ipv6, uint16_t *port, const uint8_t *tlv) {
-  /* length was already checked */
-  netaddr_from_binary(ipv6, &tlv[2], tlv[1]-2, AF_INET6);
-
-  memcpy(port, &tlv[18], sizeof(*port));
-  *port = ntohs(*port);
-}
-
-void
-dlep_parser_get_heartbeat_interval(uint64_t *interval, const uint8_t *tlv) {
-  uint16_t tmp;
-  memcpy(&tmp, &tlv[2], tlv[1]);
-
-  *interval = ntohs(tmp) * 1000;
-}
-
-void
-dlep_parser_get_mac_addr(struct netaddr *mac, const uint8_t *tlv) {
-  /* length was already checked */
-  netaddr_from_binary(mac, &tlv[2], tlv[1], AF_MAC48);
-}
-
-int
-dlep_parser_get_ipv4_addr(struct netaddr *ipv4, bool *add, const uint8_t *tlv) {
-  if (add) {
-    switch (tlv[2]) {
-      case DLEP_IP_ADD:
-        *add = true;
-        break;
-      case DLEP_IP_REMOVE:
-        *add = false;
-        break;
-      default:
-        /* bad indicator field */
-        return -1;
-    }
-  }
-  /* length was already checked */
-  netaddr_from_binary(ipv4, &tlv[3], tlv[1]-1, AF_INET);
-  return 0;
-}
-
-int
-dlep_parser_get_ipv6_addr(struct netaddr *ipv6, bool *add, const uint8_t *tlv) {
-  if (add) {
-    switch (tlv[2]) {
-      case DLEP_IP_ADD:
-        *add = true;
-        break;
-      case DLEP_IP_REMOVE:
-        *add = false;
-        break;
-      default:
-        /* bad indicator field */
-        return -1;
-    }
-  }
-
-  /* length was already checked */
-  netaddr_from_binary(ipv6, &tlv[3], tlv[1]-1, AF_INET6);
-  return 0;
-}
-
-void
-dlep_parser_get_uint64(uint64_t *number, const uint8_t *tlv) {
-  uint64_t value;
-
-  memcpy(&value, &tlv[2], sizeof(value));
-  *number= be64toh(value);
-}
-
-void
-dlep_parser_get_status(enum dlep_status *status, const uint8_t *tlv) {
-  if (tlv[2] >= DLEP_STATUS_COUNT) {
-    /* normalize status code */
-    *status = DLEP_STATUS_ERROR;
-  }
-  else {
-    *status = tlv[2];
-  }
-}
-
-void
-dlep_parser_get_extensions_supported(struct bitmap256 *bitmap, const uint8_t *tlv) {
-  unsigned i;
-
-  memset(bitmap, 0, sizeof(*bitmap));
-  for (i=0; i<tlv[1]; i++) {
-    bitmap256_set(bitmap, tlv[2+i]);
-  }
-}
-
-void
-dlep_parser_get_latency(uint32_t *latency, const uint8_t *tlv) {
-  uint32_t value;
-
-  memcpy(&value, &tlv[2], sizeof(value));
-  *latency = ntohl(value);
-}
-
-void
-dlep_parser_get_tx_signal(int32_t *sig, const uint8_t *tlv) {
-  uint32_t value;
-
-  memcpy(&value, &tlv[2], sizeof(value));
-  value = ntohl(value);
-  memcpy(sig, &value, sizeof(value));
-}
-
-void
-dlep_parser_get_rx_signal(int32_t *sig, const uint8_t *tlv) {
-  uint32_t value;
-
-  memcpy(&value, &tlv[2], sizeof(value));
-  value = ntohl(value);
-  memcpy(sig, &value, sizeof(value));
-}
-
-static int
-_check_tlv_length(uint8_t type, uint8_t length) {
-  uint8_t min, max;
-  if (type >= DLEP_TLV_COUNT) {
-    /* unsupported custom TLV, no check necessary */
-    return 0;
-  }
-
-  /* check length */
-  min = dlep_tlv_constraints[type].min_length;
-  if (min > 0 && length < min) {
-    return -1;
-  }
-  max = dlep_tlv_constraints[type].max_length;
-  if (max < 255 && length > max) {
-    return -1;
-  }
-  return 0;
-}
-
-static int
-_check_mandatory_tlvs(struct dlep_parser_index *idx,
-    uint8_t signal) {
-  struct bitmap256 *mandatory;
-  int i;
-
-  if (signal >= DLEP_SIGNAL_COUNT) {
-    /* unsupported custom signal, no check necessary */
-    return 0;
-  }
-
-  mandatory = &dlep_mandatory_tlvs_per_signal[signal];
-  for (i=0; i<DLEP_TLV_COUNT; i++) {
-    if (bitmap256_get(mandatory, i)
-        && idx->idx[i] == 0) {
-      return -1;
-    }
-  }
-  return 0;
-}
diff --git a/src-plugins/generic/dlep/dlep_parser.h b/src-plugins/generic/dlep/dlep_parser.h
deleted file mode 100644 (file)
index 6fa58d3..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-
-/*
- * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
- * Copyright (c) 2004-2015, 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 DLEP_PARSER_H_
-#define DLEP_PARSER_H_
-
-#include "common/common_types.h"
-#include "common/autobuf.h"
-#include "common/bitmap256.h"
-#include "common/netaddr.h"
-
-#include "dlep/dlep_iana.h"
-
-struct dlep_parser_index {
-  uint16_t idx[DLEP_TLV_COUNT];
-};
-
-enum dlep_parser_errors {
-  DLEP_PARSER_INCOMPLETE_HEADER     = -1,
-  DLEP_PARSER_INCOMPLETE_SIGNAL     = -2,
-  DLEP_PARSER_INCOMPLETE_TLV_HEADER = -3,
-  DLEP_PARSER_INCOMPLETE_TLV        = -4,
-  DLEP_PARSER_ILLEGAL_TLV_LENGTH    = -5,
-  DLEP_PARSER_MISSING_MANDATORY_TLV = -6,
-};
-
-int dlep_parser_read(struct dlep_parser_index *idx,
-    const void *signal, size_t len, uint16_t *siglen);
-int dlep_parser_check_mandatory_tlvs(const struct dlep_parser_index *idx,
-    const struct bitmap256 *mandatory);
-uint16_t dlep_parser_get_next_tlv(const uint8_t *buffer, size_t len, size_t offset);
-
-void dlep_parser_get_version(uint16_t *major, uint16_t *minor, const uint8_t *tlv);
-void dlep_parser_get_peer_type(char *string, const uint8_t *tlv);
-void dlep_parser_get_ipv4_conpoint(struct netaddr *ipv4, uint16_t *port, const uint8_t *tlv);
-void dlep_parser_get_ipv6_conpoint(struct netaddr *ipv4, uint16_t *port, const uint8_t *tlv);
-void dlep_parser_get_heartbeat_interval(uint64_t *interval, const uint8_t *tlv);
-void dlep_parser_get_mac_addr(struct netaddr *mac, const uint8_t *tlv);
-int dlep_parser_get_ipv4_addr(struct netaddr *ipv4, bool *add, const uint8_t *tlv);
-int dlep_parser_get_ipv6_addr(struct netaddr *ipv6, bool *add, const uint8_t *tlv);
-void dlep_parser_get_uint64(uint64_t *mdrr, const uint8_t *tlv);
-void dlep_parser_get_status(enum dlep_status *status, const uint8_t *tlv);
-void dlep_parser_get_extensions_supported(struct bitmap256 *bitmap, const uint8_t *tlv);
-void dlep_parser_get_latency(uint32_t *latency, const uint8_t *tlv);
-void dlep_parser_get_tx_signal(int32_t *sig, const uint8_t *tlv);
-void dlep_parser_get_rx_signal(int32_t *sig, const uint8_t *tlv);
-
-#endif /* DLEP_PARSER_H_ */
diff --git a/src-plugins/generic/dlep/dlep_reader.c b/src-plugins/generic/dlep/dlep_reader.c
new file mode 100644 (file)
index 0000000..76e5d3d
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * dlep_reader.c
+ *
+ *  Created on: Jun 30, 2015
+ *      Author: rogge
+ */
+
+#include "common/common_types.h"
+#include "common/netaddr.h"
+
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_session.h"
+#include "dlep/dlep_reader.h"
+
+int
+dlep_reader_heartbeat_tlv(uint64_t *interval,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  uint16_t tmp;
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_HEARTBEAT_INTERVAL_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  memcpy(&tmp, ptr, sizeof(tmp));
+  *interval = 1000ull * ntohs(tmp);
+  return 0;
+}
+
+int
+dlep_reader_peer_type(char *text, size_t text_length,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_PEER_TYPE_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+
+  if (value->length > 0 && text_length > 0) {
+    /* generate a 0 terminated copy of the text */
+    if (text_length > value->length) {
+      memcpy(text, ptr, value->length);
+      text[value->length] = 0;
+    }
+    else {
+      memcpy(text, ptr, text_length-1);
+      text[text_length-1] = 0;
+    }
+  }
+  return 0;
+}
+
+int
+dlep_reader_mac_tlv(struct netaddr *mac,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_MAC_ADDRESS_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  return netaddr_from_binary(mac, ptr, value->length, 0);
+}
+
+int
+dlep_reader_ipv4_tlv(struct netaddr *ipv4, bool *add,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_IPV4_ADDRESS_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  switch (ptr[0]) {
+    case DLEP_IP_ADD:
+      *add = true;
+      break;
+    case DLEP_IP_REMOVE:
+      *add = false;
+      break;
+    default:
+      return -1;
+  }
+  return netaddr_from_binary(ipv4, &ptr[1], 4, AF_INET);
+}
+
+int
+dlep_reader_ipv6_tlv(struct netaddr *ipv6, bool *add,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_IPV6_ADDRESS_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  switch (ptr[0]) {
+    case DLEP_IP_ADD:
+      *add = true;
+      break;
+    case DLEP_IP_REMOVE:
+      *add = false;
+      break;
+    default:
+      return -1;
+  }
+  return netaddr_from_binary(ipv6, &ptr[1], 16, AF_INET6);
+}
+
+int
+dlep_reader_ipv4_conpoint_tlv(struct netaddr *addr, uint16_t *port,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  uint16_t tmp;
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_IPV4_CONPOINT_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  if (value->length == 6) {
+    memcpy(&tmp, &ptr[4], sizeof(tmp));
+    *port = ntohs(tmp);
+  }
+  else {
+    *port = DLEP_PORT;
+  }
+
+  return netaddr_from_binary(addr, ptr, 4, AF_INET);
+}
+
+int
+dlep_reader_ipv6_conpoint_tlv(struct netaddr *addr, uint16_t *port,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  uint16_t tmp;
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_IPV6_CONPOINT_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  if (value->length == 18) {
+    memcpy(&tmp, &ptr[16], sizeof(tmp));
+    *port = ntohs(tmp);
+  }
+  else {
+    *port = DLEP_PORT;
+  }
+
+  return netaddr_from_binary(addr, ptr, 16, AF_INET6);
+}
+
+int
+dlep_reader_uint64(uint64_t *number, uint16_t tlv_id,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  uint64_t tmp;
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, tlv_id);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  memcpy(&tmp, ptr, sizeof(tmp));
+  *number = be64toh(tmp);
+  return 0;
+}
+
+int
+dlep_reader_int64(int64_t *number, uint16_t tlv_id,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  uint64_t tmp;
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, tlv_id);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  memcpy(&tmp, ptr, sizeof(tmp));
+  *number = (int64_t)(be64toh(tmp));
+  return 0;
+}
+
+int
+dlep_reader_status(enum dlep_status *status,
+    char *text, size_t text_length,
+    struct dlep_session *session, struct dlep_parser_value *value) {
+  const uint8_t *ptr;
+
+  if (!value) {
+    value = dlep_session_get_tlv_value(session, DLEP_STATUS_TLV);
+    if (!value) {
+      return -1;
+    }
+  }
+
+  ptr = dlep_session_get_tlv_binary(session, value);
+  *status = ptr[0];
+
+  if (value->length > 1 && text_length > 0) {
+    /* generate a 0 terminated copy of the text */
+    if (text_length >= value->length) {
+      memcpy(text, &ptr[1], value->length-1);
+      text[value->length-1] = 0;
+    }
+    else {
+      memcpy(text, &ptr[1], text_length-1);
+      text[text_length-1] = 0;
+    }
+  }
+  return 0;
+}
+
+int
+dlep_reader_map_identity(struct oonf_layer2_data *data,
+    struct dlep_session *session, uint16_t dlep_tlv) {
+  struct dlep_parser_value *value;
+  int64_t l2value;
+  uint64_t tmp64;
+  uint32_t tmp32;
+  uint16_t tmp16;
+  uint8_t  tmp8;
+  const uint8_t *dlepvalue;
+
+  value = dlep_session_get_tlv_value(session, dlep_tlv);
+  if (value) {
+    dlepvalue = dlep_parser_get_tlv_binary(&session->parser, value);
+
+    switch (value->length) {
+      case 8:
+        memcpy(&tmp64, dlepvalue, 8);
+        tmp64 = be64toh(tmp64);
+        break;
+      case 4:
+        memcpy(&tmp32, dlepvalue, 4);
+        tmp64 = ntohl(tmp32);
+        break;
+      case 2:
+        memcpy(&tmp16, dlepvalue, 2);
+        tmp64 = ntohs(tmp16);
+        break;
+      case 1:
+        memcpy(&tmp8, dlepvalue, 1);
+        tmp64 = tmp8;
+        break;
+      default:
+        return -1;
+    }
+
+    // TODO: dlep origin!!
+    memcpy(&l2value, &tmp64, 8);
+    oonf_layer2_set_value(data, 0, l2value);
+  }
+  return 0;
+}
+
+int
+dlep_reader_map_l2neigh_data(struct oonf_layer2_data *data,
+    struct dlep_session *session, struct dlep_extension *ext) {
+  struct dlep_neighbor_mapping *map;
+  size_t i;
+
+  for (i=0; i<ext->neigh_mapping_count; i++) {
+    map = &ext->neigh_mapping[i];
+
+    if (map->from_tlv(&data[map->layer2], session, map->dlep)) {
+      return -1;
+    }
+  }
+  return 0;
+}
diff --git a/src-plugins/generic/dlep/dlep_reader.h b/src-plugins/generic/dlep/dlep_reader.h
new file mode 100644 (file)
index 0000000..4254782
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * dlep_reader.h
+ *
+ *  Created on: Jun 30, 2015
+ *      Author: rogge
+ */
+
+#ifndef _DLEP_READER_H_
+#define _DLEP_READER_H_
+
+#include "common/common_types.h"
+#include "common/netaddr.h"
+
+#include "subsystems/oonf_layer2.h"
+
+#include "dlep/dlep_extension.h"
+
+int dlep_reader_heartbeat_tlv(uint64_t *interval,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_peer_type(char *text, size_t text_length,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_mac_tlv(struct netaddr *mac,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_ipv4_tlv(struct netaddr *ipv4, bool *add,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_ipv6_tlv(struct netaddr *ipv6, bool *add,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_ipv4_conpoint_tlv(struct netaddr *addr, uint16_t *port,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_ipv6_conpoint_tlv(struct netaddr *addr, uint16_t *port,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_uint64(uint64_t *number, uint16_t tlv_id,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_int64(int64_t *number, uint16_t tlv_id,
+    struct dlep_session *session, struct dlep_parser_value *value);
+int dlep_reader_status(enum dlep_status *status,
+    char *text, size_t text_length,
+    struct dlep_session *session, struct dlep_parser_value *value);
+
+int dlep_reader_map_identity(struct oonf_layer2_data *data,
+    struct dlep_session *session, uint16_t dlep_tlv);
+int dlep_reader_map_l2neigh_data(struct oonf_layer2_data *data,
+    struct dlep_session *session, struct dlep_extension *ext);
+
+#endif /* _DLEP_READER_H_ */
diff --git a/src-plugins/generic/dlep/dlep_session.c b/src-plugins/generic/dlep/dlep_session.c
new file mode 100644 (file)
index 0000000..3c25652
--- /dev/null
@@ -0,0 +1,779 @@
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/avl_comp.h"
+#include "core/oonf_logging.h"
+#include "subsystems/oonf_class.h"
+#include "subsystems/oonf_stream_socket.h"
+#include "subsystems/oonf_timer.h"
+
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_writer.h"
+#include "dlep/dlep_session.h"
+
+enum {
+  SESSION_VALUE_STEP = 128,
+};
+
+static int _update_allowed_tlvs(struct dlep_session_parser *parser);
+static enum dlep_parser_error _parse_tlvstream(
+    struct dlep_session_parser *parser, const uint8_t *buffer, size_t length);
+static enum dlep_parser_error _check_mandatory(
+    struct dlep_session_parser *parser, uint16_t signal_type);
+static enum dlep_parser_error _check_duplicate(
+    struct dlep_session_parser *parser, uint16_t signal_type);
+static enum dlep_parser_error _call_extension_processing(
+    struct dlep_session *parser, uint16_t signal_type);
+static struct dlep_parser_tlv *_add_session_tlv(
+    struct dlep_session_parser *parser, uint16_t id);
+static enum dlep_parser_error _process_tlvs(struct dlep_session *,
+    uint16_t signal_type, uint16_t signal_length, const uint8_t *tlvs);
+static void _send_terminate(struct dlep_session *session);
+static void _cb_destination_timeout(void *);
+
+static struct oonf_class _tlv_class = {
+    .name = "dlep reader tlv",
+    .size = sizeof(struct dlep_parser_tlv),
+};
+
+static struct oonf_class _local_neighbor_class = {
+    .name = "dlep neighbor",
+    .size = sizeof(struct dlep_local_neighbor),
+};
+
+static struct oonf_timer_class _destination_ack_class = {
+    .name = "dlep destination ack",
+    .callback = _cb_destination_timeout,
+};
+
+void
+dlep_session_init(void) {
+  oonf_class_add(&_tlv_class);
+  oonf_class_add(&_local_neighbor_class);
+  oonf_timer_add(&_destination_ack_class);
+}
+
+/**
+ * Initialize a session, will hook in the base extension
+ * @param session
+ * @return
+ */
+int
+dlep_session_add(struct dlep_session *session, const char *l2_ifname,
+    uint32_t l2_origin, struct autobuf *out, bool radio,
+    enum oonf_log_source log_source) {
+  struct dlep_session_parser *parser;
+  struct dlep_extension *ext;
+
+  parser = &session->parser;
+
+  avl_init(&parser->allowed_tlvs, avl_comp_uint16, false);
+  avl_init(&session->local_neighbor_tree, avl_comp_netaddr, false);
+
+  session->log_source = log_source;
+  session->l2_origin = l2_origin;
+  session->radio = radio;
+  session->writer.out = out;
+
+  /* remember interface name */
+  session->l2_listener.name = l2_ifname;
+
+  /* get interface listener to lock interface */
+  if ((oonf_interface_add_listener(&session->l2_listener))) {
+    OONF_WARN(session->log_source,
+        "Cannot activate interface listener for %s", l2_ifname);
+    dlep_session_remove(session);
+    return -1;
+  }
+
+  /* allocate memory for the pointers */
+  parser->extensions = calloc(1, sizeof(*ext));
+  if (!parser->extensions) {
+    OONF_WARN(session->log_source,
+        "Cannot allocate extension buffer for %s", l2_ifname);
+    dlep_session_remove(session);
+    return -1;
+  }
+
+  /* remember the sessions */
+  parser->extension_count = 1;
+
+  parser->values = calloc(SESSION_VALUE_STEP,
+      sizeof(struct dlep_parser_value));
+  if (!parser->values) {
+    OONF_WARN(session->log_source,
+        "Cannot allocate values buffer for %s", l2_ifname);
+    dlep_session_remove(session);
+    return -1;
+  }
+
+  parser->extensions[0] = dlep_extension_get(DLEP_EXTENSION_BASE);
+  if (!parser->extensions[0]) {
+    OONF_WARN(session->log_source,
+        "default extension not found");
+    dlep_session_remove(session);
+    return -1;
+  }
+
+  if (_update_allowed_tlvs(parser)) {
+    OONF_WARN(session->log_source,
+        "Could not update allowed TLVs for %s", l2_ifname);
+    dlep_session_remove(session);
+    return -1;
+  }
+
+  OONF_INFO(session->log_source, "Add session on %s",
+      session->l2_listener.name);
+  return 0;
+}
+
+void
+dlep_session_remove(struct dlep_session *session) {
+  struct dlep_parser_tlv *tlv, *tlv_it;
+  struct dlep_session_parser *parser;
+  struct netaddr_str nbuf;
+
+  OONF_DEBUG(session->log_source, "Remove session if %s to %s",
+      session->l2_listener.name,
+      netaddr_socket_to_string(&nbuf, &session->remote_socket));
+
+  oonf_interface_remove_listener(&session->l2_listener);
+
+  parser = &session->parser;
+  avl_for_each_element_safe(&parser->allowed_tlvs, tlv, _node, tlv_it) {
+    avl_remove(&parser->allowed_tlvs, &tlv->_node);
+    oonf_class_free(&_tlv_class, tlv);
+  }
+
+  oonf_timer_stop(&session->local_event_timer);
+  oonf_timer_stop(&session->remote_heartbeat_timeout);
+
+  free (parser->extensions);
+  parser->extensions = NULL;
+
+  free (parser->values);
+  parser->values = NULL;
+}
+
+/**
+ * Send peer termination
+ * @param session dlep session
+ */
+void
+dlep_session_terminate(struct dlep_session *session) {
+  if (session->next_signal != DLEP_ALL_SIGNALS) {
+    return;
+  }
+
+  dlep_session_generate_signal(
+      session, DLEP_PEER_TERMINATION, NULL);
+  session->cb_send_buffer(session, 0);
+  session->next_signal = DLEP_PEER_TERMINATION_ACK;
+}
+
+int
+dlep_session_update_extensions(struct dlep_session *session,
+    const uint8_t *extvalues, size_t extcount) {
+  struct dlep_extension **ext_array, *ext;
+  size_t count, i;
+  uint16_t extid;
+
+  /* keep entry 0 untouched, that is the base extension */
+  count = 1;
+  for (i=0; i<extcount; i++) {
+    memcpy(&extid, &extvalues[i*2], sizeof(extid));
+
+    if (dlep_extension_get(ntohs(extid))) {
+      count++;
+    }
+  }
+
+  if (count != session->parser.extension_count) {
+    ext_array = realloc(session->parser.extensions,
+        sizeof(struct dlep_extension *) * count);
+    if (!ext_array) {
+      return -1;
+    }
+
+    session->parser.extensions = ext_array;
+    session->parser.extension_count = count;
+  }
+
+  count = 1;
+  for (i=1; i<extcount; i++) {
+    memcpy(&extid, &extvalues[i*2], sizeof(extid));
+    if ((ext = dlep_extension_get(ntohs(extid)))) {
+      session->parser.extensions[count] = ext;
+      count++;
+    }
+  }
+
+  _update_allowed_tlvs(&session->parser);
+  return 0;
+}
+
+enum oonf_stream_session_state
+dlep_session_process_tcp(struct oonf_stream_session *tcp_session,
+    struct dlep_session *session) {
+  ssize_t processed;
+
+  OONF_DEBUG(session->log_source,
+      "Process TCP buffer of %" PRINTF_SIZE_T_SPECIFIER " bytes",
+      abuf_getlen(&tcp_session->in));
+
+  processed = dlep_session_process_buffer(session,
+      abuf_getptr(&tcp_session->in),
+      abuf_getlen(&tcp_session->in));
+
+  OONF_DEBUG(session->log_source,
+      "Processed %" PRINTF_SSIZE_T_SPECIFIER " bytes", processed);
+  if (processed < 0) {
+    return STREAM_SESSION_CLEANUP;
+  }
+
+  abuf_pull(&tcp_session->in, processed);
+
+  if (abuf_getlen(session->writer.out) > 0) {
+    OONF_DEBUG(session->log_source,
+        "Trigger sending %" PRINTF_SIZE_T_SPECIFIER " bytes",
+        abuf_getlen(session->writer.out));
+
+    /* send answer */
+    oonf_stream_flush(tcp_session);
+  }
+  if (session->next_signal == DLEP_KILL_SESSION) {
+    return STREAM_SESSION_CLEANUP;
+  }
+  return STREAM_SESSION_ACTIVE;
+}
+
+ssize_t
+dlep_session_process_buffer(
+    struct dlep_session *session, const void *buffer, size_t length) {
+  ssize_t result, offset;
+  const char *ptr;
+
+  offset = 0;
+  ptr = buffer;
+
+  OONF_DEBUG(session->log_source, "Processing buffer of"
+      " %" PRINTF_SIZE_T_SPECIFIER " bytes", length);
+  while (length > 0) {
+    OONF_DEBUG(session->log_source, "Processing message at offset"
+        " %" PRINTF_SSIZE_T_SPECIFIER, offset);
+
+    if ((result = dlep_session_process_signal(
+        session, &ptr[offset], length)) <= 0){
+      if (result < 0) {
+        return result;
+      }
+      break;
+    }
+
+    length -= result;
+    offset += result;
+  }
+  return offset;
+}
+
+size_t
+dlep_session_process_signal(struct dlep_session *session,
+    const void *ptr, size_t length) {
+  enum dlep_parser_error result;
+  uint16_t signal_type;
+  uint16_t signal_length;
+  const uint8_t *buffer;
+  struct netaddr_str nbuf;
+
+  if (length < 4) {
+    /* not enough data for a signal type */
+    OONF_DEBUG(session->log_source, "Not enough data to process"
+        " signal from %s (%" PRINTF_SIZE_T_SPECIFIER" bytes)",
+        netaddr_socket_to_string(&nbuf, &session->remote_socket),
+        length);
+
+    return 0;
+  }
+
+  buffer = ptr;
+
+  /* copy data */
+  memcpy(&signal_type, &buffer[0], sizeof(signal_type));
+  memcpy(&signal_length, &buffer[2], sizeof(signal_length));
+  signal_type = ntohs(signal_type);
+  signal_length = ntohs(signal_length);
+
+  if (length < (size_t)signal_length + 4u) {
+    /* not enough data for signal */
+    OONF_DEBUG(session->log_source, "Not enough data to process"
+        " signal %u (length %u) from %s"
+        " (%" PRINTF_SIZE_T_SPECIFIER" bytes)",
+        signal_type, signal_length,
+        netaddr_socket_to_string(&nbuf, &session->remote_socket),
+        length);
+    return 0;
+  }
+
+  OONF_DEBUG(session->log_source, "Process signal %u (length %u)"
+      " from %s (%" PRINTF_SIZE_T_SPECIFIER" bytes)",
+      signal_type, signal_length,
+      netaddr_socket_to_string(&nbuf, &session->remote_socket),
+      length);
+
+  if (session->next_signal != DLEP_ALL_SIGNALS
+      && session->next_signal != signal_type) {
+    OONF_DEBUG(session->log_source, "Signal should have been %u,"
+        " drop session", session->next_signal);
+    /* we only accept a single type and we got the wrong one */
+    return -1;
+  }
+
+  result = _process_tlvs(session,
+      signal_type, signal_length, &buffer[4]);
+  if (result != DLEP_NEW_PARSER_OKAY) {
+    OONF_WARN(session->log_source, "Parser error: %d", result);
+    _send_terminate(session);
+  }
+
+  /* skip forward */
+  return signal_length + 4;
+}
+
+struct dlep_local_neighbor *
+dlep_session_add_local_neighbor(struct dlep_session *session,
+    const struct netaddr *neigh) {
+  struct dlep_local_neighbor *local;
+  if ((local = dlep_session_get_local_neighbor(session, neigh))) {
+    return local;
+  }
+
+  local = oonf_class_malloc(&_local_neighbor_class);
+  if (!local) {
+    return NULL;
+  }
+
+  /* hook into tree */
+  memcpy(&local->addr, neigh, sizeof(local->addr));
+  local->_node.key = &local->addr;
+  avl_insert(&session->local_neighbor_tree, &local->_node);
+
+  /* initialize timer */
+  local->_ack_timeout.class = &_destination_ack_class;
+  local->_ack_timeout.cb_context = local;
+
+  /* initialize backpointer */
+  local->session = session;
+
+  return local;
+}
+
+void
+dlep_session_remove_local_neighbor(struct dlep_session *session,
+    struct dlep_local_neighbor *local) {
+  avl_remove(&session->local_neighbor_tree, &local->_node);
+  oonf_timer_stop(&local->_ack_timeout);
+  oonf_class_free(&_local_neighbor_class, local);
+}
+
+struct dlep_local_neighbor *
+dlep_session_get_local_neighbor(struct dlep_session *session,
+    const struct netaddr *neigh) {
+  struct dlep_local_neighbor *local;
+  return avl_find_element(&session->local_neighbor_tree,
+      neigh, local, _node);
+}
+
+static int
+_generate_signal(struct dlep_session *session, uint16_t signal,
+    const struct netaddr *neighbor) {
+  struct dlep_extension *ext;
+  size_t e,s, len;
+  struct netaddr_str nbuf1, nbuf2;
+
+  OONF_DEBUG(session->log_source, "Generate signal %u for %s on %s (%s)",
+      signal, netaddr_to_string(&nbuf1, neighbor),
+      session->l2_listener.name,
+      netaddr_socket_to_string(&nbuf2, &session->remote_socket));
+
+  len = abuf_getlen(session->writer.out);
+
+  /* generate signal */
+  dlep_writer_start_signal(&session->writer, signal);
+  for (e=0; e<session->parser.extension_count; e++) {
+    ext = session->parser.extensions[e];
+
+    for (s=0; s<ext->signal_count; s++) {
+      if (ext->signals[s].id != signal) {
+        continue;
+      }
+
+      if (session->radio && ext->signals[s].add_radio_tlvs) {
+        OONF_DEBUG(session->log_source,
+            "Add tlvs for radio extension %d", ext->id);
+        if (ext->signals[s].add_radio_tlvs(session, neighbor)) {
+          return -1;
+        }
+      }
+      else if (!session->radio && ext->signals[s].add_router_tlvs) {
+        OONF_DEBUG(session->log_source,
+            "Add tlvs for router extension %d", ext->id);
+        if (ext->signals[s].add_router_tlvs(session, neighbor)) {
+          return -1;
+        }
+      }
+      break;
+    }
+  }
+
+  OONF_DEBUG(session->log_source, "generated %" PRIu64 " bytes",
+      abuf_getlen(session->writer.out) - len);
+  return 0;
+}
+
+int
+dlep_session_generate_signal(struct dlep_session *session, uint16_t signal,
+    const struct netaddr *neighbor) {
+  if (_generate_signal(session, signal, neighbor)) {
+    OONF_DEBUG(session->log_source, "Could not generate signal");
+    return -1;
+  }
+  return dlep_writer_finish_signal(&session->writer, session->log_source);
+}
+
+int
+dlep_session_generate_signal_status(struct dlep_session *session,
+    uint16_t signal, const struct netaddr *neighbor,
+    enum dlep_status status, const char *msg) {
+  if (_generate_signal(session, signal, neighbor)) {
+    return -1;
+  }
+  if (dlep_writer_add_status(&session->writer, status, msg)) {
+    return -1;
+  }
+  return dlep_writer_finish_signal(&session->writer, session->log_source);
+}
+
+struct dlep_parser_value *
+dlep_session_get_tlv_value(
+    struct dlep_session *session, uint16_t tlvtype) {
+  struct dlep_parser_tlv *tlv;
+
+  tlv = dlep_parser_get_tlv(&session->parser, tlvtype);
+  if (tlv) {
+    return dlep_session_get_tlv_first_value(session, tlv);
+  }
+  return NULL;
+}
+
+static int
+_update_allowed_tlvs(struct dlep_session_parser *parser) {
+  struct dlep_parser_tlv *tlv, *tlv_it;
+  struct dlep_extension *ext;
+  size_t e, t;
+  uint16_t id;
+
+  /* remove all existing allowed tlvs */
+  avl_for_each_element_safe(&parser->allowed_tlvs, tlv, _node, tlv_it) {
+    avl_remove(&parser->allowed_tlvs, &tlv->_node);
+    oonf_class_free(&_tlv_class, tlv);
+  }
+
+  /* allocate new allowed tlvs structures */
+  for (e = 0; e < parser->extension_count; e++) {
+    ext = parser->extensions[e];
+
+    /* for all extensions */
+    for (t = 0; t < ext->tlv_count; t++) {
+      /* for all tlvs */
+      id = ext->tlvs[t].id;
+      tlv = dlep_parser_get_tlv(parser, id);
+      if (!tlv) {
+        /* new tlv found! */
+        if (!(tlv = _add_session_tlv(parser, id))) {
+          return -1;
+        }
+        tlv->length_min = ext->tlvs[t].length_min;
+        tlv->length_max = ext->tlvs[t].length_max;
+      }
+      else if (
+          tlv->length_min != ext->tlvs[t].length_min
+          || tlv->length_max != ext->tlvs[t].length_max) {
+        return -1;
+      }
+    }
+  }
+  return 0;
+}
+
+static enum dlep_parser_error
+_process_tlvs(struct dlep_session *session,
+    uint16_t signal_type, uint16_t signal_length, const uint8_t *tlvs) {
+  struct dlep_session_parser *parser;
+  enum dlep_parser_error result;
+
+  parser = &session->parser;
+
+  /* start at the beginning of the tlvs */
+  if ((result = _parse_tlvstream(parser, tlvs, signal_length))) {
+    OONF_DEBUG(session->log_source, "parse_tlvstream result: %d", result);
+    return result;
+  }
+  if ((result = _check_mandatory(parser, signal_type))) {
+    OONF_DEBUG(session->log_source, "check_mandatory result: %d", result);
+    return result;
+  }
+  if ((result = _check_duplicate(parser, signal_type))) {
+    OONF_DEBUG(session->log_source, "check_duplicate result: %d", result);
+    return result;
+  }
+
+  if ((result = _call_extension_processing(session, signal_type))) {
+    OONF_DEBUG(session->log_source,
+        "extension processing failed: %d", result);
+    return result;
+  }
+
+  return DLEP_NEW_PARSER_OKAY;
+}
+
+static void
+_send_terminate(struct dlep_session *session) {
+  if (session->next_signal != DLEP_PEER_DISCOVERY
+      && session->next_signal != DLEP_PEER_OFFER) {
+    dlep_session_generate_signal(session, DLEP_PEER_TERMINATION, NULL);
+
+    session->next_signal = DLEP_PEER_TERMINATION_ACK;
+  }
+}
+
+static void
+_cb_destination_timeout(void *ptr) {
+  struct dlep_local_neighbor *local;
+
+  local = ptr;
+  if (local->session->cb_destination_timeout) {
+    local->session->cb_destination_timeout(local->session, local);
+  }
+}
+
+static enum dlep_parser_error
+_parse_tlvstream(struct dlep_session_parser *parser,
+    const uint8_t *buffer, size_t length) {
+  struct dlep_parser_tlv *tlv;
+  struct dlep_parser_value *value;
+  uint16_t tlv_type;
+  uint16_t tlv_length;
+  size_t tlv_count, idx;
+  int i;
+
+  parser->tlv_ptr = buffer;
+  tlv_count = 0;
+  idx = 0;
+
+  avl_for_each_element(&parser->allowed_tlvs, tlv, _node) {
+    tlv->tlv_first = -1;
+    tlv->tlv_last = -1;
+  }
+
+  while (idx < length) {
+    if (length - idx < 4) {
+      /* too short for a TLV, end parsing */
+      return DLEP_NEW_PARSER_INCOMPLETE_TLV_HEADER;
+    }
+
+    /* copy header */
+    memcpy(&tlv_type, &buffer[idx], sizeof(tlv_type));
+    idx += sizeof(tlv_type);
+    tlv_type = ntohs(tlv_type);
+
+    memcpy(&tlv_length, &buffer[idx], sizeof(tlv_length));
+    idx += sizeof(tlv_length);
+    tlv_length = ntohs(tlv_length);
+
+    if (idx + tlv_length > length) {
+      return DLEP_NEW_PARSER_INCOMPLETE_TLV;
+    }
+
+    /* check if tlv is supported */
+    tlv = dlep_parser_get_tlv(parser, tlv_type);
+    if (!tlv) {
+      return DLEP_NEW_PARSER_UNSUPPORTED_TLV;
+    }
+
+    /* check length */
+    if (tlv->length_max < tlv_length || tlv->length_min > tlv_length) {
+      return DLEP_NEW_PARSER_ILLEGAL_TLV_LENGTH;
+    }
+
+    /* check if we need to allocate more space for value pointers */
+    if (parser->value_max_count == tlv_count) {
+      /* allocate more */
+      value = realloc(parser->values,
+          sizeof(*value) * tlv_count + SESSION_VALUE_STEP);
+      if (!value) {
+        return DLEP_NEW_PARSER_OUT_OF_MEMORY;
+      }
+      parser->value_max_count += SESSION_VALUE_STEP;
+      parser->values = value;
+    }
+
+    /* remember tlv value */
+    value = &parser->values[tlv_count];
+    value->tlv_next = -1;
+    value->index = idx;
+    value->length = tlv_length;
+
+    if (tlv->tlv_last == -1) {
+      /* first tlv */
+      tlv->tlv_first = tlv_count;
+    }
+    else {
+      /* one more */
+      value = &parser->values[tlv->tlv_last];
+      value->tlv_next = tlv_count;
+    }
+    tlv->tlv_last  = tlv_count;
+    tlv_count++;
+
+    idx += tlv_length;
+  }
+
+  avl_for_each_element(&parser->allowed_tlvs, tlv, _node) {
+    i = tlv->tlv_first;
+    while (i != -1) {
+      value = &parser->values[i];
+
+      i = value->tlv_next;
+    }
+  }
+  return DLEP_NEW_PARSER_OKAY;
+}
+
+static enum dlep_parser_error
+_check_mandatory(struct dlep_session_parser *parser, uint16_t signal_type) {
+  struct dlep_parser_tlv *tlv;
+  struct dlep_extension_signal *extsig;
+  struct dlep_extension *ext;
+  size_t e,s,t;
+
+  for (e = 0; e < parser->extension_count; e++) {
+    ext = parser->extensions[e];
+
+    extsig = NULL;
+    for (s = 0; s < ext->signal_count; s++) {
+      extsig = &ext->signals[s];
+      if (ext->signals[s].id == signal_type) {
+        extsig = &ext->signals[s];
+        break;
+      }
+    }
+
+    if (extsig) {
+      for (t = 0; t < extsig->mandatory_tlv_count; t++) {
+        tlv = dlep_parser_get_tlv(parser, extsig->mandatory_tlvs[t]);
+        if (!tlv) {
+          return DLEP_NEW_PARSER_INTERNAL_ERROR;
+        }
+
+        if (tlv->tlv_first == -1) {
+          return DLEP_NEW_PARSER_MISSING_MANDATORY_TLV;
+        }
+      }
+    }
+  }
+  return DLEP_NEW_PARSER_OKAY;
+}
+
+static enum dlep_parser_error
+_check_duplicate(struct dlep_session_parser *parser, uint16_t signal_type) {
+  struct dlep_parser_tlv *tlv;
+  struct dlep_extension_signal *extsig;
+  struct dlep_extension *ext;
+  size_t e, s, t;
+  bool okay;
+
+  avl_for_each_element(&parser->allowed_tlvs, tlv, _node) {
+    if (tlv->tlv_first == tlv->tlv_last) {
+      continue;
+    }
+
+    /* multiple tlvs of the same kind */
+    okay = false;
+    for (e = 0; e < parser->extension_count && !okay; e++) {
+      ext = parser->extensions[e];
+
+      extsig = NULL;
+      for (s = 0; s < ext->signal_count; s++) {
+        extsig = &ext->signals[s];
+        if (ext->signals[s].id == signal_type) {
+          extsig = &ext->signals[s];
+          break;
+        }
+      }
+
+      if (extsig) {
+        for (t = 0; t < extsig->duplicate_tlv_count; t++) {
+          if (extsig->duplicate_tlvs[t] == tlv->id) {
+            okay = true;
+            break;
+          }
+        }
+      }
+    }
+    if (!okay) {
+      return DLEP_NEW_PARSER_DUPLICATE_TLV;
+    }
+  }
+  return DLEP_NEW_PARSER_OKAY;
+}
+
+static enum dlep_parser_error
+_call_extension_processing(struct dlep_session *session, uint16_t signal_type) {
+  struct dlep_extension *ext;
+  size_t e, s;
+
+  for (e=0; e<session->parser.extension_count; e++) {
+    ext = session->parser.extensions[e];
+
+    for (s=0; s<ext->signal_count; s++) {
+      if (ext->signals[s].id != signal_type) {
+        continue;
+      }
+
+      if (session->radio) {
+        if (ext->signals[s].process_radio(session)) {
+          OONF_DEBUG(session->log_source,
+              "Error in radio signal processing of extension '%s'", ext->name);
+          return -1;
+        }
+      }
+      else {
+        if (ext->signals[s].process_router(session)) {
+          OONF_DEBUG(session->log_source,
+              "Error in router signal processing of extension '%s'", ext->name);
+          return -1;
+        }
+      }
+      break;
+    }
+  }
+  return DLEP_NEW_PARSER_OKAY;
+}
+
+static struct dlep_parser_tlv *
+_add_session_tlv(struct dlep_session_parser *parser, uint16_t id) {
+  struct dlep_parser_tlv *tlv;
+
+  tlv = oonf_class_malloc(&_tlv_class);
+  if (!tlv) {
+    return NULL;
+  }
+
+  tlv->id = id;
+  tlv->_node.key = &tlv->id;
+  tlv->tlv_first = -1;
+  tlv->tlv_last  = -1;
+
+  avl_insert(&parser->allowed_tlvs, &tlv->_node);
+  return tlv;
+}
diff --git a/src-plugins/generic/dlep/dlep_session.h b/src-plugins/generic/dlep/dlep_session.h
new file mode 100644 (file)
index 0000000..f26309a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * dlep_session.h
+ *
+ *  Created on: Jun 26, 2015
+ *      Author: rogge
+ */
+
+#ifndef _DLEP_SESSION_H_
+#define _DLEP_SESSION_H_
+
+struct dlep_session;
+struct dlep_writer;
+
+#include "common/common_types.h"
+#include "common/avl.h"
+#include "common/autobuf.h"
+#include "common/netaddr.h"
+#include "subsystems/oonf_layer2.h"
+#include "subsystems/oonf_interface.h"
+#include "subsystems/oonf_stream_socket.h"
+#include "subsystems/oonf_timer.h"
+#include "subsystems/os_interface_data.h"
+
+#include "dlep/dlep_extension.h"
+#include "dlep/dlep_iana.h"
+
+enum dlep_parser_error {
+  DLEP_NEW_PARSER_OKAY                  =  0,
+  DLEP_NEW_PARSER_INCOMPLETE_TLV_HEADER = -1,
+  DLEP_NEW_PARSER_INCOMPLETE_TLV        = -2,
+  DLEP_NEW_PARSER_UNSUPPORTED_TLV       = -3,
+  DLEP_NEW_PARSER_ILLEGAL_TLV_LENGTH    = -4,
+  DLEP_NEW_PARSER_MISSING_MANDATORY_TLV = -5,
+  DLEP_NEW_PARSER_DUPLICATE_TLV         = -6,
+  DLEP_NEW_PARSER_OUT_OF_MEMORY         = -7,
+  DLEP_NEW_PARSER_INTERNAL_ERROR        = -8,
+};
+
+struct dlep_parser_tlv {
+    /* tlv id */
+    uint16_t id;
+
+    /* index of first session value for tlv */
+    int32_t tlv_first, tlv_last;
+
+    /* minimal and maximal length of tlv */
+    uint16_t length_min, length_max;
+
+    /* node for session tlv tree */
+    struct avl_node _node;
+};
+
+struct dlep_parser_value {
+    /* index of next session value */
+    int32_t tlv_next;
+
+    /* index of value within signal buffer */
+    uint16_t index;
+
+    /* length of tlv in bytes */
+    uint16_t length;
+};
+
+struct dlep_session_parser {
+    struct avl_tree allowed_tlvs;
+
+    struct dlep_parser_value *values;
+    size_t value_max_count;
+
+    /* array of active dlep extensions */
+    struct dlep_extension **extensions;
+    size_t extension_count;
+
+    /* start of signals tlvs that is has been parsed */
+    const uint8_t *tlv_ptr;
+
+    /* neighbor MAC a signal is referring to */
+    struct netaddr signal_neighbor_mac;
+};
+
+struct dlep_writer {
+    struct autobuf *out;
+
+    uint16_t signal_type;
+    char *signal_start_ptr;
+};
+
+enum dlep_neighbor_state {
+  DLEP_NEIGHBOR_IDLE       = 0,
+  DLEP_NEIGHBOR_UP_SENT    = 1,
+  DLEP_NEIGHBOR_UP_ACKED   = 2,
+  DLEP_NEIGHBOR_DOWN_SENT  = 3,
+  DLEP_NEIGHBOR_DOWN_ACKED = 4,
+};
+
+struct dlep_local_neighbor {
+    struct netaddr addr;
+    enum dlep_neighbor_state state;
+    bool changed;
+
+    struct netaddr neigh_addr;
+
+    struct dlep_session *session;
+
+    struct oonf_timer_instance _ack_timeout;
+    struct avl_node _node;
+};
+
+struct dlep_session_config {
+    /* peer type of local session */
+    const char *peer_type;
+
+    /* discovery interval */
+    uint64_t discovery_interval;
+
+    /* heartbeat settings for our heartbeats */
+    uint64_t heartbeat_interval;
+
+    /* true if normal neighbors should be sent with DLEP */
+    bool send_neighbors;
+
+    /* true if proxied neighbors should be sent with DLEP */
+    bool send_proxied;
+};
+
+struct dlep_session {
+    /* copy of local configuration */
+    struct dlep_session_config cfg;
+
+    /* next expected signal for session */
+    enum dlep_signals next_signal;
+
+    /* true if this is a radio session */
+    bool radio;
+
+    /* parser for this dlep session */
+    struct dlep_session_parser parser;
+
+    /* signal writer*/
+    struct dlep_writer writer;
+
+    /* tree of local neighbors being processed by DLEP */
+    struct avl_tree local_neighbor_tree;
+
+    /* oonf layer2 origin for dlep session */
+    uint32_t l2_origin;
+
+    /* send content of output buffer */
+    void (*cb_send_buffer)(struct dlep_session *, int af_family);
+
+    /* terminate the current session */
+    void (*cb_end_session)(struct dlep_session *);
+
+    /* handle timeout for destination */
+    void (*cb_destination_timeout)(struct dlep_session *,
+        struct dlep_local_neighbor *);
+
+    /* log source for usage of this session */
+    enum oonf_log_source log_source;
+
+    /* local layer2 data interface */
+    struct oonf_interface_listener l2_listener;
+
+    /* timer to generate discovery/heartbeats */
+    struct oonf_timer_instance local_event_timer;
+
+    /* keep track of remote heartbeats */
+    struct oonf_timer_instance remote_heartbeat_timeout;
+
+    /* rate of remote heartbeats */
+    uint64_t remote_heartbeat_interval;
+
+    /* remote endpoint of current communication */
+    union netaddr_socket remote_socket;
+
+    /* remember all streams bound to an interface */
+    struct avl_node _node;
+};
+
+void dlep_session_init(void);
+
+int dlep_session_add(struct dlep_session *session,
+    const char *l2_ifname, uint32_t l2_origin,
+    struct autobuf *out, bool radio, enum oonf_log_source);
+void dlep_session_remove(struct dlep_session *session);
+void dlep_session_terminate(struct dlep_session *session);
+
+int dlep_session_update_extensions(struct dlep_session *session,
+    const uint8_t *extvalues, size_t extcount);
+enum oonf_stream_session_state dlep_session_process_tcp(
+    struct oonf_stream_session *tcp_session,
+    struct dlep_session *session);
+ssize_t dlep_session_process_buffer(
+    struct dlep_session *session, const void *buffer, size_t length);
+size_t dlep_session_process_signal(struct dlep_session *session,
+    const void *buffer, size_t length);
+int dlep_session_generate_signal(struct dlep_session *session,
+    uint16_t signal, const struct netaddr *neighbor);
+int dlep_session_generate_signal_status(struct dlep_session *session,
+    uint16_t signal, const struct netaddr *neighbor,
+    enum dlep_status status, const char *msg);
+struct dlep_parser_value *dlep_session_get_tlv_value(
+    struct dlep_session *session, uint16_t tlvtype);
+
+struct dlep_local_neighbor *dlep_session_add_local_neighbor(
+    struct dlep_session *session, const struct netaddr *neigh);
+void dlep_session_remove_local_neighbor(
+    struct dlep_session *session, struct dlep_local_neighbor *local);
+struct dlep_local_neighbor *dlep_session_get_local_neighbor(
+    struct dlep_session *session, const struct netaddr *neigh);
+
+static INLINE struct dlep_parser_tlv *
+dlep_parser_get_tlv(struct dlep_session_parser *parser, uint16_t tlvtype) {
+    struct dlep_parser_tlv *tlv;
+  return avl_find_element(&parser->allowed_tlvs, &tlvtype, tlv, _node);
+}
+
+static INLINE struct dlep_parser_value *
+dlep_session_get_tlv_first_value(struct dlep_session *session,
+    struct dlep_parser_tlv *tlv) {
+  if (tlv->tlv_first == -1) {
+    return NULL;
+  }
+  return &session->parser.values[tlv->tlv_first];
+}
+
+static INLINE struct dlep_parser_value *
+dlep_session_get_next_tlv_value(struct dlep_session *session,
+    struct dlep_parser_value *value) {
+  if (value->tlv_next == -1) {
+    return NULL;
+  }
+  return &session->parser.values[value->tlv_next];
+}
+
+static INLINE const uint8_t *
+dlep_parser_get_tlv_binary(struct dlep_session_parser *parser,
+    struct dlep_parser_value *value) {
+  return &parser->tlv_ptr[value->index];
+}
+
+static INLINE const uint8_t *
+dlep_session_get_tlv_binary(struct dlep_session *session,
+    struct dlep_parser_value *value) {
+  return &session->parser.tlv_ptr[value->index];
+}
+
+#endif /* _DLEP_SESSION_H_ */
diff --git a/src-plugins/generic/dlep/dlep_static_data.c b/src-plugins/generic/dlep/dlep_static_data.c
deleted file mode 100644 (file)
index 524642a..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-
-/*
- * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
- * Copyright (c) 2004-2015, 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 "common/common_types.h"
-
-#include "dlep/dlep_iana.h"
-#include "dlep/dlep_static_data.h"
-
-struct bitmap256 dlep_mandatory_signals = { .b = {
-  (1ull << DLEP_PEER_DISCOVERY )
-  | (1ull << DLEP_PEER_OFFER )
-  | (1ull << DLEP_PEER_INITIALIZATION )
-  | (1ull << DLEP_PEER_INITIALIZATION_ACK )
-  | (1ull << DLEP_PEER_TERMINATION )
-  | (1ull << DLEP_PEER_TERMINATION_ACK )
-  | (1ull << DLEP_DESTINATION_UP )
-  | (1ull << DLEP_DESTINATION_UPDATE )
-  | (1ull << DLEP_DESTINATION_DOWN )
-  | (1ull << DLEP_HEARTBEAT),
-  0,0,0
-}};
-
-struct bitmap256 dlep_supported_optional_signals = { .b = {
-  (1ull << DLEP_PEER_TERMINATION)
-  | (1ull << DLEP_PEER_TERMINATION_ACK)
-  | (1ull << DLEP_DESTINATION_UP_ACK)
-  | (1ull << DLEP_DESTINATION_DOWN_ACK),
-  0,0,0
-}};
-
-struct bitmap256 dlep_mandatory_tlvs_per_signal[DLEP_SIGNAL_COUNT] = {
-  [DLEP_PEER_DISCOVERY] = { .b = {
-      (1ull << DLEP_VERSION_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_OFFER] = { .b = {
-      (1ull << DLEP_VERSION_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_INITIALIZATION] = { .b = {
-      (1ull << DLEP_VERSION_TLV)
-      | (1ull << DLEP_HEARTBEAT_INTERVAL_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_INITIALIZATION_ACK] = { .b = {
-      (1ull << DLEP_VERSION_TLV)
-      | (1ull << DLEP_HEARTBEAT_INTERVAL_TLV)
-      | (1ull << DLEP_MDRR_TLV)
-      | (1ull << DLEP_MDRT_TLV)
-      | (1ull << DLEP_CDRR_TLV)
-      | (1ull << DLEP_CDRT_TLV)
-      | (1ull << DLEP_LATENCY_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_TERMINATION] = { .b = {
-      0,0,0,0
-  }},
-  [DLEP_PEER_TERMINATION_ACK] = { .b = {
-      0,0,0,0
-  }},
-  [DLEP_DESTINATION_UP] = { .b = {
-      (1ull << DLEP_MAC_ADDRESS_TLV)
-  }},
-  [DLEP_DESTINATION_UP_ACK] = { .b = {
-      (1ull << DLEP_MAC_ADDRESS_TLV)
-  }},
-  [DLEP_DESTINATION_DOWN] = { .b = {
-      (1ull << DLEP_MAC_ADDRESS_TLV)
-  }},
-  [DLEP_DESTINATION_DOWN_ACK] = { .b = {
-      (1ull << DLEP_MAC_ADDRESS_TLV)
-  }},
-  [DLEP_DESTINATION_UPDATE] = { .b = {
-      (1ull << DLEP_MAC_ADDRESS_TLV)
-  }},
-};
-
-struct bitmap256 dlep_supported_optional_tlvs_per_signal[DLEP_SIGNAL_COUNT] = {
-  [DLEP_PEER_DISCOVERY] = { .b = {
-      (1ull << DLEP_PEER_TYPE_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_OFFER] = { .b = {
-      (1ull << DLEP_PEER_TYPE_TLV)
-      | (1ull << DLEP_IPV4_CONPOINT_TLV)
-      | (1ull << DLEP_IPV6_CONPOINT_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_INITIALIZATION] = { .b = {
-      (1ull << DLEP_PEER_TYPE_TLV)
-      | (1ull << DLEP_EXTENSIONS_SUPPORTED)
-      | (1ull << DLEP_EXPERIMENTAL_DEFINITION),
-      0,0,0
-  }},
-  [DLEP_PEER_INITIALIZATION_ACK] = { .b = {
-      (1ull << DLEP_PEER_TYPE_TLV)
-      | (1ull << DLEP_EXTENSIONS_SUPPORTED)
-      | (1ull << DLEP_STATUS_TLV)
-      | (1ull << DLEP_FRAMES_R_TLV)
-      | (1ull << DLEP_FRAMES_T_TLV)
-      | (1ull << DLEP_BYTES_R_TLV)
-      | (1ull << DLEP_BYTES_T_TLV)
-      | (1ull << DLEP_FRAMES_RETRIES_TLV)
-      | (1ull << DLEP_FRAMES_FAILED_TLV)
-      | (1ull << DLEP_RX_SIGNAL_TLV)
-      | (1ull << DLEP_TX_SIGNAL_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_TERMINATION] = { .b = {
-      (1ull << DLEP_STATUS_TLV),
-      0,0,0
-  }},
-  [DLEP_PEER_TERMINATION_ACK] = { .b = {
-      (1ull << DLEP_STATUS_TLV),
-      0,0,0
-  }},
-  [DLEP_DESTINATION_UP] = { .b = {
-      (1ull << DLEP_MDRR_TLV)
-      | (1ull << DLEP_MDRT_TLV)
-      | (1ull << DLEP_CDRR_TLV)
-      | (1ull << DLEP_CDRT_TLV)
-      | (1ull << DLEP_LATENCY_TLV)
-      | (1ull << DLEP_FRAMES_R_TLV)
-      | (1ull << DLEP_FRAMES_T_TLV)
-      | (1ull << DLEP_BYTES_R_TLV)
-      | (1ull << DLEP_BYTES_T_TLV)
-      | (1ull << DLEP_FRAMES_RETRIES_TLV)
-      | (1ull << DLEP_FRAMES_FAILED_TLV)
-      | (1ull << DLEP_TX_SIGNAL_TLV)
-      | (1ull << DLEP_RX_SIGNAL_TLV),
-      0,0,0
-  }},
-  [DLEP_DESTINATION_UP_ACK] = { .b = {
-      (1ull << DLEP_STATUS_TLV),
-      0,0,0
-  }},
-  [DLEP_DESTINATION_DOWN] = { .b = {
-      0,0,0,0
-  }},
-  [DLEP_DESTINATION_DOWN_ACK] = { .b = {
-      (1ull << DLEP_STATUS_TLV),
-      0,0,0
-  }},
-  [DLEP_DESTINATION_UPDATE] = { .b = {
-      (1ull << DLEP_MDRR_TLV)
-      | (1ull << DLEP_MDRT_TLV)
-      | (1ull << DLEP_CDRR_TLV)
-      | (1ull << DLEP_CDRT_TLV)
-      | (1ull << DLEP_LATENCY_TLV)
-      | (1ull << DLEP_FRAMES_R_TLV)
-      | (1ull << DLEP_FRAMES_T_TLV)
-      | (1ull << DLEP_BYTES_R_TLV)
-      | (1ull << DLEP_BYTES_T_TLV)
-      | (1ull << DLEP_FRAMES_RETRIES_TLV)
-      | (1ull << DLEP_FRAMES_FAILED_TLV)
-      | (1ull << DLEP_TX_SIGNAL_TLV)
-      | (1ull << DLEP_RX_SIGNAL_TLV),
-      0,0,0
-  }},
-};
-
-struct dlep_tlvdata dlep_tlv_constraints[DLEP_TLV_COUNT] = {
-    [DLEP_VERSION_TLV] = { 4,4 },
-    [DLEP_STATUS_TLV] = { 1,255 },
-    [DLEP_IPV4_CONPOINT_TLV] = { 6,6 },
-    [DLEP_IPV6_CONPOINT_TLV] = { 18,18 },
-    [DLEP_PEER_TYPE_TLV] = { 1,255 },
-    [DLEP_HEARTBEAT_INTERVAL_TLV] = { 2,2 },
-    [DLEP_EXTENSIONS_SUPPORTED] = { 1,255 },
-    [DLEP_EXPERIMENTAL_DEFINITION] = { 1,255 },
-    [DLEP_MAC_ADDRESS_TLV] = { 6,6 },
-    [DLEP_IPV4_ADDRESS_TLV] = { 5,5 },
-    [DLEP_IPV6_ADDRESS_TLV] = { 17,17 },
-    [DLEP_IPV4_SUBNET_TLV] = { 5,5 },
-    [DLEP_IPV6_SUBNET_TLV] = { 17,17 },
-    [DLEP_MDRR_TLV] = { 8,8 },
-    [DLEP_MDRT_TLV] = { 8,8 },
-    [DLEP_CDRR_TLV] = { 8,8 },
-    [DLEP_CDRT_TLV] = { 8,8 },
-    [DLEP_LATENCY_TLV] = { 4,4 },
-    [DLEP_RESR_TLV] = { 1,1 },
-    [DLEP_REST_TLV] = { 1,1 },
-    [DLEP_RLQR_TLV] = { 1,1 },
-    [DLEP_RLQT_TLV] = { 1,1 },
-    [DLEP_LINK_CHAR_ACK_TIMER_TLV] = { 1,1 },
-    [DLEP_CREDIT_GRANT_TLV] = { 8,8 },
-    [DLEP_CREDIT_WIN_STATUS_TLV] = { 16,16 },
-    [DLEP_CREDIT_REQUEST_TLV] = { 1,1 },
-
-    [DLEP_FRAMES_R_TLV] = { 8,8 },
-    [DLEP_FRAMES_T_TLV] = { 8,8 },
-    [DLEP_BYTES_R_TLV] = { 8,8 },
-    [DLEP_BYTES_T_TLV] = { 8,8 },
-    [DLEP_FRAMES_RETRIES_TLV] = { 8,8 },
-    [DLEP_FRAMES_FAILED_TLV] = { 8,8 },
-    [DLEP_TX_SIGNAL_TLV] = { 4,4 },
-    [DLEP_RX_SIGNAL_TLV] = { 4,4 },
-};
diff --git a/src-plugins/generic/dlep/dlep_static_data.h b/src-plugins/generic/dlep/dlep_static_data.h
deleted file mode 100644 (file)
index 9ab0c1c..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-
-/*
- * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
- * Copyright (c) 2004-2015, 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 DLEP_TLVDATA_H_
-#define DLEP_TLVDATA_H_
-
-#include "common/bitmap256.h"
-#include "common/common_types.h"
-
-#include "dlep/dlep_iana.h"
-
-struct dlep_tlvdata {
-  uint8_t min_length;
-  uint8_t max_length;
-};
-
-extern struct bitmap256 dlep_mandatory_signals;
-extern struct bitmap256 dlep_mandatory_tlvs;
-extern struct bitmap256 dlep_mandatory_tlvs_per_signal[DLEP_SIGNAL_COUNT];
-extern struct bitmap256 dlep_supported_optional_tlvs_per_signal[DLEP_SIGNAL_COUNT];
-extern struct bitmap256 dlep_supported_optional_signals;
-extern struct bitmap256 dlep_supported_optional_tlvs;
-
-extern struct dlep_tlvdata dlep_tlv_constraints[DLEP_TLV_COUNT];
-
-#endif /* DLEP_TLVDATA_H_ */
index 343dd66..eda81e3 100644 (file)
 #include <arpa/inet.h>
 
 #include "common/common_types.h"
-#include "common/bitmap256.h"
 #include "common/autobuf.h"
 
 #include "core/oonf_logging.h"
-#include "subsystems/oonf_packet_socket.h"
-#include "subsystems/oonf_stream_socket.h"
 
+#include "dlep/dlep_extension.h"
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_static_data.h"
 #include "dlep/dlep_writer.h"
 
 #ifndef _BSD_SOURCE
 #endif
 #include <endian.h> /* htobe64 */
 
-static struct autobuf _signal_buf;
-static uint8_t _signal_id;
+void
+dlep_writer_start_signal(struct dlep_writer *writer, uint16_t signal_type) {
 
-int
-dlep_writer_init(void) {
-  return abuf_init(&_signal_buf);
-}
+  writer->signal_type = signal_type;
+  writer->signal_start_ptr =
+      abuf_getptr(writer->out) + abuf_getlen(writer->out);
 
-void
-dlep_writer_cleanup(void) {
-  abuf_free(&_signal_buf);
+  abuf_append_uint16(writer->out, htons(signal_type));
+  abuf_append_uint16(writer->out, 0);
 }
 
 void
-dlep_writer_start_signal(uint8_t signal) {
-  _signal_id = signal;
-  abuf_clear(&_signal_buf);
-  abuf_append_uint8(&_signal_buf, signal);
-  abuf_append_uint16(&_signal_buf, 0);
+dlep_writer_add_tlv(struct dlep_writer *writer,
+    uint16_t type, const void *data, uint16_t len) {
+  abuf_append_uint16(writer->out, htons(type));
+  abuf_append_uint16(writer->out, htons(len));
+  abuf_memcpy(writer->out, data, len);
 }
 
 void
-dlep_writer_add_tlv(uint8_t type, void *data, uint8_t len) {
-  if (bitmap256_get(&dlep_mandatory_tlvs_per_signal[_signal_id], type)
-      || bitmap256_get(&dlep_supported_optional_tlvs_per_signal[_signal_id], type)) {
-    abuf_append_uint8(&_signal_buf, type);
-    abuf_append_uint8(&_signal_buf, len);
-    abuf_memcpy(&_signal_buf, data, len);
-  }
+dlep_writer_add_tlv2(struct dlep_writer *writer,
+    uint16_t type, const void *data1, uint16_t len1,
+    const void *data2, uint16_t len2) {
+  abuf_append_uint16(writer->out, htons(type));
+  abuf_append_uint16(writer->out, htons(len1 + len2));
+  abuf_memcpy(writer->out, data1, len1);
+  abuf_memcpy(writer->out, data2, len2);
 }
 
 int
-dlep_writer_finish_signal(enum oonf_log_source source) {
-  uint16_t len;
-  char *ptr;
+dlep_writer_finish_signal(struct dlep_writer *writer,
+    enum oonf_log_source source) {
+  size_t length;
+  uint16_t buffer;
 
-  if (abuf_has_failed(&_signal_buf)) {
+  if (abuf_has_failed(writer->out)) {
     OONF_WARN(source, "Could not build signal: %u",
-        abuf_getptr(&_signal_buf)[0]);
+        writer->signal_type);
     return -1;
   }
 
-  if (abuf_getlen(&_signal_buf) > 65535 - 3) {
+  length = (abuf_getptr(writer->out) + abuf_getlen(writer->out))
+      - writer->signal_start_ptr;
+  if (length > 65535 + 4) {
     OONF_WARN(source, "Signal %u became too long: %" PRINTF_SIZE_T_SPECIFIER,
-        abuf_getptr(&_signal_buf)[0], abuf_getlen(&_signal_buf));
+        writer->signal_type, abuf_getlen(writer->out));
     return -1;
   }
 
   /* calculate network ordered size */
-  len = htons(abuf_getlen(&_signal_buf)-3);
+  buffer = htons(length - 4);
 
   /* put it into the signal */
-  ptr = abuf_getptr(&_signal_buf);
-  memcpy(&ptr[1], &len, sizeof(len));
+  memcpy(&writer->signal_start_ptr[2], &buffer, sizeof(buffer));
 
   return 0;
 }
 
 void
-dlep_writer_send_udp_multicast(struct oonf_packet_managed *managed,
-    enum oonf_log_source source) {
-  OONF_DEBUG_HEX(source, abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf),
-      "Send signal via UDP multicast");
-
-  if (oonf_packet_send_managed_multicast(
-      managed, abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf), AF_INET)) {
-    OONF_WARN(source, "Could not send ipv4 multicast signal");
-  }
-  if (oonf_packet_send_managed_multicast(
-      managed, abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf), AF_INET6)) {
-    OONF_WARN(source, "Could not send ipv6 multicast signal");
-  }
-}
-
-void
-dlep_writer_send_udp_unicast(struct oonf_packet_managed *managed,
-    union netaddr_socket *dst, enum oonf_log_source source) {
-  struct netaddr_str nbuf;
-
-  OONF_DEBUG_HEX(source, abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf),
-      "Send signal via udp unicast");
-
-  if (oonf_packet_send_managed(
-      managed, dst, abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf))) {
-    OONF_WARN(source, "Could not send udp unicast to %s",
-        netaddr_socket_to_string(&nbuf, dst));
-  }
-}
-
-void
-dlep_writer_send_tcp_unicast(struct oonf_stream_session *session,
-    enum oonf_log_source source __attribute__((unused))) {
-  OONF_DEBUG_HEX(source, abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf),
-      "Send signal via TCP");
-  abuf_memcpy(&session->out,
-      abuf_getptr(&_signal_buf), abuf_getlen(&_signal_buf));
-  oonf_stream_flush(session);
-}
-
-void
-dlep_writer_add_version_tlv(uint16_t major, uint16_t minor) {
-  uint16_t value[2];
+dlep_writer_add_heartbeat_tlv(struct dlep_writer *writer, uint64_t interval) {
+  uint16_t value;
 
-  value[0] = htons(major);
-  value[1] = htons(minor);
+  value = htons(interval / 1000);
 
-  dlep_writer_add_tlv(DLEP_VERSION_TLV, &value, sizeof(value));
+  dlep_writer_add_tlv(writer, DLEP_HEARTBEAT_INTERVAL_TLV,
+      &value, sizeof(value));
 }
 
 void
-dlep_writer_add_heartbeat_tlv(uint64_t interval) {
-  uint16_t value;
-
-  value = htons(interval / 1000);
-
-  dlep_writer_add_tlv(DLEP_HEARTBEAT_INTERVAL_TLV, &value, sizeof(value));
+dlep_writer_add_peer_type_tlv(struct dlep_writer *writer,
+    const char *peer_type) {
+  dlep_writer_add_tlv(writer, DLEP_PEER_TYPE_TLV,
+      peer_type, strlen(peer_type));
 }
 
 int
-dlep_writer_add_mac_tlv(const struct netaddr *mac) {
-  uint8_t value[6];
-
-  if (netaddr_get_address_family(mac) != AF_MAC48) {
-    return -1;
+dlep_writer_add_mac_tlv(struct dlep_writer *writer,
+    const struct netaddr *mac) {
+  uint8_t value[8];
+
+  switch (netaddr_get_address_family(mac)) {
+    case AF_MAC48:
+    case AF_EUI64:
+      break;
+    default:
+      return -1;
   }
 
-  netaddr_to_binary(value, mac, 6);
+  netaddr_to_binary(value, mac, 8);
 
-  dlep_writer_add_tlv(DLEP_MAC_ADDRESS_TLV, value, sizeof(value));
+  dlep_writer_add_tlv(writer,
+      DLEP_MAC_ADDRESS_TLV, value, netaddr_get_binlength(mac));
   return 0;
 }
 
 int
-dlep_writer_add_ipv4_tlv(const struct netaddr *ipv4, bool add) {
+dlep_writer_add_ipv4_tlv(struct dlep_writer *writer,
+    const struct netaddr *ipv4, bool add) {
   uint8_t value[5];
 
   if (netaddr_get_address_family(ipv4) != AF_INET) {
@@ -201,12 +162,14 @@ dlep_writer_add_ipv4_tlv(const struct netaddr *ipv4, bool add) {
   value[0] = add ? DLEP_IP_ADD : DLEP_IP_REMOVE;
   netaddr_to_binary(&value[1], ipv4, 4);
 
-  dlep_writer_add_tlv(DLEP_IPV4_ADDRESS_TLV, value, sizeof(value));
+  dlep_writer_add_tlv(writer,
+      DLEP_IPV4_ADDRESS_TLV, value, sizeof(value));
   return 0;
 }
 
 int
-dlep_writer_add_ipv6_tlv(const struct netaddr *ipv6, bool add) {
+dlep_writer_add_ipv6_tlv(struct dlep_writer *writer,
+    const struct netaddr *ipv6, bool add) {
   uint8_t value[17];
 
   if (netaddr_get_address_family(ipv6) != AF_INET6) {
@@ -216,12 +179,14 @@ dlep_writer_add_ipv6_tlv(const struct netaddr *ipv6, bool add) {
   value[0] = add ? DLEP_IP_ADD : DLEP_IP_REMOVE;
   netaddr_to_binary(&value[1], ipv6, 16);
 
-  dlep_writer_add_tlv(DLEP_IPV6_ADDRESS_TLV, value, sizeof(value));
+  dlep_writer_add_tlv(writer,
+      DLEP_IPV6_ADDRESS_TLV, value, sizeof(value));
   return 0;
 }
 
 void
-dlep_writer_add_ipv4_conpoint_tlv(const struct netaddr *addr, uint16_t port) {
+dlep_writer_add_ipv4_conpoint_tlv(struct dlep_writer *writer,
+    const struct netaddr *addr, uint16_t port) {
   uint8_t value[6];
 
   if (netaddr_get_address_family(addr) != AF_INET) {
@@ -235,11 +200,13 @@ dlep_writer_add_ipv4_conpoint_tlv(const struct netaddr *addr, uint16_t port) {
   netaddr_to_binary(&value[0], addr, sizeof(value));
   memcpy(&value[4], &port, sizeof(port));
 
-  dlep_writer_add_tlv(DLEP_IPV4_CONPOINT_TLV, &value, sizeof(value));
+  dlep_writer_add_tlv(writer,
+      DLEP_IPV4_CONPOINT_TLV, &value, sizeof(value));
 }
 
 void
-dlep_writer_add_ipv6_conpoint_tlv(const struct netaddr *addr, uint16_t port) {
+dlep_writer_add_ipv6_conpoint_tlv(struct dlep_writer *writer,
+    const struct netaddr *addr, uint16_t port) {
   uint8_t value[18];
 
   if (netaddr_get_address_family(addr) != AF_INET6) {
@@ -253,60 +220,105 @@ dlep_writer_add_ipv6_conpoint_tlv(const struct netaddr *addr, uint16_t port) {
   netaddr_to_binary(&value[0], addr, sizeof(value));
   memcpy(&value[16], &port, sizeof(port));
 
-  dlep_writer_add_tlv(DLEP_IPV6_CONPOINT_TLV, &value, sizeof(value));
-}
-
-void
-dlep_writer_add_latency(uint32_t latency) {
-  latency = htonl(latency);
-
-  dlep_writer_add_tlv(DLEP_LATENCY_TLV, &latency, sizeof(latency));
+  dlep_writer_add_tlv(writer,
+      DLEP_IPV6_CONPOINT_TLV, &value, sizeof(value));
 }
 
 void
-dlep_writer_add_uint64(uint64_t number, enum dlep_tlvs tlv) {
+dlep_writer_add_uint64(struct dlep_writer *writer,
+    uint64_t number, enum dlep_tlvs tlv) {
   uint64_t value;
 
   value = be64toh(number);
 
-  dlep_writer_add_tlv(tlv, &value, sizeof(value));
+  dlep_writer_add_tlv(writer, tlv, &value, sizeof(value));
 }
 
 void
-dlep_writer_add_status(enum dlep_status status) {
-  uint8_t value = status;
+dlep_writer_add_int64(struct dlep_writer *writer,
+    int64_t number, enum dlep_tlvs tlv) {
+  uint64_t *value = (uint64_t*)(&number);
 
-  dlep_writer_add_tlv(DLEP_STATUS_TLV, &value, sizeof(value));
-}
+  *value = htonl(*value);
 
-void
-dlep_writer_add_extensions_supported(void) {
-  uint8_t value[DLEP_SIGNAL_COUNT];
-  size_t i,j;
+  dlep_writer_add_tlv(writer, tlv, value, sizeof(*value));
+}
 
-  for (i=0,j=0; i<DLEP_SIGNAL_COUNT; i++) {
-    if (bitmap256_get(&dlep_supported_optional_signals, i)) {
-      value[j++] = i;
-    }
+int
+dlep_writer_add_status(struct dlep_writer *writer,
+    enum dlep_status status, const char *text) {
+  uint8_t value;
+  size_t txtlen;
+
+  value = status;
+  txtlen = strlen(text);
+  if (txtlen > 65534) {
+    return -1;
   }
 
-  dlep_writer_add_tlv(DLEP_EXTENSIONS_SUPPORTED, &value[0], j);
+  dlep_writer_add_tlv2(writer, DLEP_STATUS_TLV,
+      &value, sizeof(value), text, txtlen);
+  return 0;
 }
 
 void
-dlep_writer_add_rx_signal(int32_t signal) {
-  uint32_t *value = (uint32_t*)(&signal);
+dlep_writer_add_supported_extensions(struct dlep_writer *writer,
+    const uint16_t *extensions, uint16_t ext_count) {
+  dlep_writer_add_tlv(writer, DLEP_EXTENSIONS_SUPPORTED_TLV,
+      extensions, ext_count * 2);
+}
 
-  *value = htonl(*value);
+int
+dlep_writer_map_identity(struct dlep_writer *writer,
+    struct oonf_layer2_data *data, uint16_t tlv, uint16_t length) {
+  int64_t l2value;
+  uint64_t tmp64;
+  uint32_t tmp32;
+  uint16_t tmp16;
+  uint8_t tmp8;
+  void *value;
+
+  l2value = oonf_layer2_get_value(data);
+  memcpy(&tmp64, &l2value, 8);
+
+  switch (length) {
+    case 8:
+      tmp64 = htobe64(tmp64);
+      value = &tmp64;
+      break;
+    case 4:
+      tmp32 = htonl(tmp64);
+      value = &tmp32;
+      break;
+    case 2:
+      tmp16 = htons(tmp64);
+      value = &tmp16;
+      break;
+    case 1:
+      tmp8 = tmp64;
+      value = &tmp8;
+      break;
+    default:
+      return -1;
+  }
 
-  dlep_writer_add_tlv(DLEP_RX_SIGNAL_TLV, value, sizeof(*value));
+  dlep_writer_add_tlv(writer, tlv, value, length);
+  return 0;
 }
 
-void
-dlep_writer_add_tx_signal(int32_t signal) {
-  uint32_t *value = (uint32_t*)(&signal);
+int
+dlep_writer_map_l2neigh_data(struct dlep_writer *writer,
+    struct dlep_extension *ext, struct oonf_layer2_data *data) {
+  struct dlep_neighbor_mapping *map;
+  size_t i;
 
-  *value = htonl(*value);
+  for (i=0; i<ext->neigh_mapping_count; i++) {
+    map = &ext->neigh_mapping[i];
 
-  dlep_writer_add_tlv(DLEP_TX_SIGNAL_TLV, value, sizeof(*value));
+    if (map->to_tlv(writer, &data[map->layer2],
+        map->dlep, map->length)) {
+      return -1;
+    }
+  }
+  return 0;
 }
index b80d326..075ea4e 100644 (file)
 
 #include "common/common_types.h"
 #include "common/autobuf.h"
-#include "common/bitmap256.h"
 #include "common/netaddr.h"
 
-#include "core/oonf_logging.h"
-#include "subsystems/oonf_stream_socket.h"
+#include "subsystems/oonf_layer2.h"
 
+#include "dlep/dlep_session.h"
 
-int dlep_writer_init(void);
-void dlep_writer_cleanup(void);
-
-void dlep_writer_start_signal(uint8_t signal);
-void dlep_writer_add_tlv(uint8_t type, void *data,
-    uint8_t len);
-int dlep_writer_finish_signal(enum oonf_log_source);
-
-void dlep_writer_send_udp_multicast(struct oonf_packet_managed *managed,
-    enum oonf_log_source source);
-void dlep_writer_send_udp_unicast(struct oonf_packet_managed *managed,
-    union netaddr_socket *dst, enum oonf_log_source source);
-void dlep_writer_send_tcp_unicast(struct oonf_stream_session *session,
+void dlep_writer_start_signal(struct dlep_writer *writer,
+    uint16_t signal_type);
+void dlep_writer_add_tlv(struct dlep_writer *writer,
+    uint16_t type, const void *data, uint16_t len);
+void dlep_writer_add_tlv2(struct dlep_writer *writer,
+    uint16_t type, const void *data1, uint16_t len1,
+    const void *data2, uint16_t len2);
+int dlep_writer_finish_signal(struct dlep_writer *writer,
     enum oonf_log_source source);
+void dlep_writer_add_heartbeat_tlv(struct dlep_writer *writer,
+    uint64_t interval);
+void dlep_writer_add_peer_type_tlv(struct dlep_writer *writer,
+    const char *peer_type);
+int dlep_writer_add_mac_tlv(struct dlep_writer *writer,
+    const struct netaddr *mac);
+int dlep_writer_add_ipv4_tlv(struct dlep_writer *writer,
+    const struct netaddr *ipv4, bool add);
+int dlep_writer_add_ipv6_tlv(struct dlep_writer *writer,
+    const struct netaddr *ipv6, bool add);
+void dlep_writer_add_ipv4_conpoint_tlv(struct dlep_writer *writer,
+    const struct netaddr *addr, uint16_t port);
+void dlep_writer_add_ipv6_conpoint_tlv(struct dlep_writer *writer,
+    const struct netaddr *addr, uint16_t port);
+void dlep_writer_add_uint64(struct dlep_writer *writer,
+    uint64_t number, enum dlep_tlvs tlv);
+void dlep_writer_add_int64(struct dlep_writer *writer,
+    int64_t number, enum dlep_tlvs tlv);
+int dlep_writer_add_status(struct dlep_writer *writer,
+    enum dlep_status status, const char *text);
+void dlep_writer_add_supported_extensions(struct dlep_writer *writer,
+    const uint16_t *extensions, uint16_t ext_count);
 
-void dlep_writer_add_version_tlv(uint16_t major, uint16_t minor);
-void dlep_writer_add_ipv4_conpoint_tlv(const struct netaddr *addr, uint16_t port);
-void dlep_writer_add_ipv6_conpoint_tlv(const struct netaddr *addr, uint16_t port);
-void dlep_writer_add_heartbeat_tlv(uint64_t interval);
-int dlep_writer_add_mac_tlv(const struct netaddr *mac);
-int dlep_writer_add_ipv4_tlv(const struct netaddr *, bool add);
-int dlep_writer_add_ipv6_tlv(const struct netaddr *, bool add);
-void dlep_writer_add_latency(uint32_t latency);
-void dlep_writer_add_uint64(uint64_t number, enum dlep_tlvs tlv);
-void dlep_writer_add_status(enum dlep_status status);
-void dlep_writer_add_extensions_supported(void);
-void dlep_writer_add_tx_signal(int32_t signal);
-void dlep_writer_add_rx_signal(int32_t signal);
+int dlep_writer_map_identity(struct dlep_writer *writer,
+    struct oonf_layer2_data *data, uint16_t tlv, uint16_t length);
+int dlep_writer_map_l2neigh_data(struct dlep_writer *writer,
+    struct dlep_extension *ext, struct oonf_layer2_data *data);
 
 #endif /* DLEP_WRITER_H_ */
index 8256d3f..28ae116 100644 (file)
@@ -56,8 +56,6 @@
 #include "subsystems/oonf_timer.h"
 
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
 #include "dlep/dlep_writer.h"
 #include "dlep/radio/dlep_radio.h"
 #include "dlep/radio/dlep_radio_interface.h"
@@ -73,29 +71,32 @@ static void _cb_config_changed(void);
 
 /* configuration */
 static struct cfg_schema_entry _radio_entries[] = {
-  CFG_MAP_STRING_ARRAY(dlep_radio_if, udp_config.interface, "datapath_if", "",
+  CFG_MAP_STRING_ARRAY(dlep_radio_if, interf.udp_config.interface, "datapath_if", "",
      "Name of interface to talk to dlep router (default is section name)", IF_NAMESIZE),
 
-  CFG_MAP_NETADDR_V4(dlep_radio_if, udp_config.multicast_v4, "discovery_mc_v4",
+  CFG_MAP_NETADDR_V4(dlep_radio_if, interf.udp_config.multicast_v4, "discovery_mc_v4",
     DLEP_WELL_KNOWN_MULTICAST_ADDRESS, "IPv4 address to send discovery UDP packet to", false, false),
-  CFG_MAP_NETADDR_V6(dlep_radio_if, udp_config.multicast_v6, "discovery_mc_v6",
+  CFG_MAP_NETADDR_V6(dlep_radio_if, interf.udp_config.multicast_v6, "discovery_mc_v6",
     DLEP_WELL_KNOWN_MULTICAST_ADDRESS_6, "IPv6 address to send discovery UDP packet to", false, false),
-  CFG_MAP_INT32_MINMAX(dlep_radio_if, udp_config.port, "discovery_port",
+  CFG_MAP_INT32_MINMAX(dlep_radio_if, interf.udp_config.port, "discovery_port",
     DLEP_WELL_KNOWN_MULTICAST_PORT_TXT, "UDP port for discovery packets", 0, false, 1, 65535),
-  CFG_MAP_ACL_V46(dlep_radio_if, udp_config.bindto, "discovery_bindto", "fe80::/10",
+  CFG_MAP_ACL_V46(dlep_radio_if, interf.udp_config.bindto, "discovery_bindto", "fe80::/10",
     "Filter to determine the binding of the UDP discovery socket"),
 
   CFG_MAP_INT32_MINMAX(dlep_radio_if, tcp_config.port, "session_port",
     "12345", "Server port for DLEP tcp sessions", 0, false, 1, 65535),
   CFG_MAP_ACL_V46(dlep_radio_if, tcp_config.bindto, "session_bindto", "fe80::/10",
       "Filter to determine the binding of the TCP server socket"),
-  CFG_MAP_CLOCK_MINMAX(dlep_radio_if, local_heartbeat_interval,
+  CFG_MAP_CLOCK_MINMAX(dlep_radio_if, interf.session.cfg.heartbeat_interval,
       "heartbeat_interval", "1.000",
       "Interval in seconds between two heartbeat signals", 1000, 65535 * 1000),
 
-  CFG_MAP_BOOL(dlep_radio_if, use_proxied_dst, "proxied", "false",
+  CFG_MAP_BOOL(dlep_radio_if, interf.single_session, "single_session", "true",
+      "Connect only to a single router"),
+
+  CFG_MAP_BOOL(dlep_radio_if, interf.session.cfg.send_proxied, "proxied", "false",
       "Report 802.11s proxied mac address for neighbors"),
-  CFG_MAP_BOOL(dlep_radio_if, use_nonproxied_dst, "not_proxied", "true",
+  CFG_MAP_BOOL(dlep_radio_if, interf.session.cfg.send_neighbors, "not_proxied", "true",
       "Report direct neighbors"),
 };
 
@@ -149,10 +150,6 @@ _early_cfg_init(void) {
  */
 static int
 _init(void) {
-  if (dlep_writer_init()) {
-    return -1;
-  }
-
   dlep_radio_interface_init();
   return 0;
 }
@@ -171,7 +168,6 @@ _initiate_shutdown(void) {
 static void
 _cleanup(void) {
   dlep_radio_interface_cleanup();
-  dlep_writer_cleanup();
 }
 
 /**
@@ -183,7 +179,7 @@ _cb_config_changed(void) {
 
   if (!_radio_section.post) {
     /* remove old interface object */
-    interface = dlep_radio_get_interface(_radio_section.section_name);
+    interface = dlep_radio_get_by_layer2_if(_radio_section.section_name);
     if (interface) {
       dlep_radio_remove_interface(interface);
     }
@@ -204,13 +200,15 @@ _cb_config_changed(void) {
     return;
   }
 
-  if (!interface->udp_config.interface[0]) {
-    strscpy(interface->udp_config.interface, _radio_section.section_name,
-        sizeof(interface->udp_config.interface));
+  if (!interface->interf.udp_config.interface[0]) {
+    strscpy(interface->interf.udp_config.interface,
+        _radio_section.section_name,
+        sizeof(interface->interf.udp_config.interface));
   }
 
   /* apply interface name also to TCP socket */
-  strscpy(interface->tcp_config.interface, interface->udp_config.interface,
+  strscpy(interface->tcp_config.interface,
+      interface->interf.udp_config.interface,
       sizeof(interface->tcp_config.interface));
 
   /* apply settings */
index c3645f6..0a005da 100644 (file)
 #include "subsystems/oonf_stream_socket.h"
 #include "subsystems/oonf_timer.h"
 
+#include "dlep/dlep_extension.h"
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
+#include "dlep/dlep_session.h"
 #include "dlep/dlep_writer.h"
+#include "dlep/dlep_base/dlep_base_radio.h"
 #include "dlep/radio/dlep_radio.h"
 #include "dlep/radio/dlep_radio_interface.h"
 #include "dlep/radio/dlep_radio_internal.h"
 #include "dlep/radio/dlep_radio_session.h"
 
-static void _cb_receive_udp(struct oonf_packet_socket *,
-    union netaddr_socket *from, void *ptr, size_t length);
-
-static void _handle_peer_discovery(struct dlep_radio_if *interface,
-    union netaddr_socket *dst, uint8_t *buffer, struct dlep_parser_index *idx);
-
-static void _generate_peer_offer(
-    struct dlep_radio_if *interface, union netaddr_socket *dst);
+static void _cleanup_interface(struct dlep_radio_if *interface);
 
 /* DLEP interfaces */
-struct avl_tree dlep_radio_if_tree;
+static struct avl_tree _interface_tree;
 
 static struct oonf_class _interface_class = {
   .name = "DLEP radio session",
@@ -79,14 +73,20 @@ static bool _shutting_down;
 /**
  * Initialize everything for dlep radio interfaces. This function also
  * initializes the dlep sessions.
+ * @return -1 if an error happened, 0 otherwise
  */
-void
+int
 dlep_radio_interface_init(void) {
   oonf_class_add(&_interface_class);
-  avl_init(&dlep_radio_if_tree, avl_comp_strcasecmp, false);
+  avl_init(&_interface_tree, avl_comp_strcasecmp, false);
 
+  dlep_extension_init();
+  dlep_session_init();
   dlep_radio_session_init();
+  dlep_base_radio_init();
+
   _shutting_down = false;
+  return 0;
 }
 
 /**
@@ -97,7 +97,7 @@ void
 dlep_radio_interface_cleanup(void) {
   struct dlep_radio_if *interf, *it;
 
-  avl_for_each_element_safe(&dlep_radio_if_tree, interf, _node, it) {
+  avl_for_each_element_safe(&_interface_tree, interf, interf._node, it) {
     dlep_radio_remove_interface(interf);
   }
 
@@ -106,28 +106,28 @@ dlep_radio_interface_cleanup(void) {
 }
 
 /**
- * Get a dlep radio interface by name
- * @param ifname interface name
+ * Get a dlep radio interface by layer2 interface name
+ * @param l2_ifname interface name
  * @return dlep radio interface, NULL if not found
  */
 struct dlep_radio_if *
-dlep_radio_get_interface(const char *ifname) {
+dlep_radio_get_by_layer2_if(const char *l2_ifname) {
   struct dlep_radio_if *interf;
 
-  return avl_find_element(&dlep_radio_if_tree, ifname, interf, l2_source);
+  return avl_find_element(&_interface_tree, l2_ifname, interf, interf._node);
 }
 
 /**
- * Get a dlep radio interface by name
+ * Get a dlep radio interface by dlep datapath name
  * @param ifname interface name
  * @return dlep radio interface, NULL if not found
  */
 struct dlep_radio_if *
-dlep_radio_get_by_source_if(const char *ifname) {
+dlep_radio_get_by_datapath_if(const char *ifname) {
   struct dlep_radio_if *interf;
 
-  avl_for_each_element(&dlep_radio_if_tree, interf, _node) {
-    if (strcmp(interf->l2_source, ifname) == 0) {
+  avl_for_each_element(&_interface_tree, interf, interf._node) {
+    if (strcmp(interf->interf.udp_config.interface, ifname) == 0) {
       return interf;
     }
   }
@@ -144,7 +144,7 @@ struct dlep_radio_if *
 dlep_radio_add_interface(const char *ifname) {
   struct dlep_radio_if *interface;
 
-  interface = dlep_radio_get_interface(ifname);
+  interface = dlep_radio_get_by_layer2_if(ifname);
   if (interface) {
     return interface;
   }
@@ -154,20 +154,13 @@ dlep_radio_add_interface(const char *ifname) {
     return NULL;
   }
 
-  /* initialize key */
-  strscpy(interface->l2_source, ifname, sizeof(interface->l2_source));
-  interface->_node.key = interface->l2_source;
+  if (dlep_if_add(&interface->interf, ifname, 0, LOG_DLEP_RADIO, true)) {
+    oonf_class_free(&_interface_class, interface);
+    return NULL;
+  }
 
   /* add to global tree of sessions */
-  avl_insert(&dlep_radio_if_tree, &interface->_node);
-
-  /* initialize session tree */
-  avl_init(&interface->session_tree, avl_comp_netaddr_socket, false);
-
-  /* initialize discovery socket */
-  interface->udp.config.user = interface;
-  interface->udp.config.receive_data = _cb_receive_udp;
-  oonf_packet_add_managed(&interface->udp);
+  avl_insert(&_interface_tree, &interface->interf._node);
 
   /* configure TCP server socket */
   interface->tcp.config.session_timeout = 120000; /* 120 seconds */
@@ -186,14 +179,20 @@ dlep_radio_add_interface(const char *ifname) {
  */
 void
 dlep_radio_remove_interface(struct dlep_radio_if *interface) {
-  /* cleanup discovery socket */
-  oonf_packet_remove_managed(&interface->udp, true);
+  /* close all sessions */
+  _cleanup_interface(interface);
 
   /* cleanup tcp socket */
   oonf_stream_remove_managed(&interface->tcp, true);
 
-  /* remove tcp */
-  avl_remove(&dlep_radio_if_tree, &interface->_node);
+  /* cleanup generic interface */
+  dlep_if_remove(&interface->interf);
+
+  /* remove from interface tree */
+  avl_remove(&_interface_tree, &interface->interf._node);
+
+  /* free memory */
+  abuf_free(&interface->interf.udp_out);
   oonf_class_free(&_interface_class, interface);
 }
 
@@ -203,8 +202,16 @@ dlep_radio_remove_interface(struct dlep_radio_if *interface) {
  */
 void
 dlep_radio_apply_interface_settings(struct dlep_radio_if *interface) {
-  oonf_packet_apply_managed(&interface->udp, &interface->udp_config);
+  struct dlep_extension *ext;
+
+  oonf_packet_apply_managed(&interface->interf.udp, &interface->interf.udp_config);
   oonf_stream_apply_managed(&interface->tcp, &interface->tcp_config);
+
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (ext->cb_session_apply_router) {
+      ext->cb_session_apply_radio(&interface->interf.session);
+    }
+  }
 }
 
 /**
@@ -213,111 +220,27 @@ dlep_radio_apply_interface_settings(struct dlep_radio_if *interface) {
 void
 dlep_radio_terminate_all_sessions(void) {
   struct dlep_radio_if *interf;
-  struct dlep_radio_session *session;
+  struct dlep_radio_session *radio_session;
 
   _shutting_down = true;
 
-  avl_for_each_element(&dlep_radio_if_tree, interf, _node) {
-    avl_for_each_element(&interf->session_tree, session, _node) {
-      dlep_radio_terminate_session(session);
+  avl_for_each_element(&_interface_tree, interf, interf._node) {
+    avl_for_each_element(&interf->interf.session_tree, radio_session, _node) {
+      dlep_session_terminate(&radio_session->session);
     }
   }
 }
 
 /**
- * Callback for handle incoming UDP packets for DLEP
- * via oonf_packet_managed API.
- * @param pkt packet socket
- * @param from IP socket UDP was coming from
- * @param ptr begin of UDP data
- * @param length length of UDP data
- */
-static void
-_cb_receive_udp(struct oonf_packet_socket *pkt,
-    union netaddr_socket *from, void *ptr, size_t length) {
-  struct dlep_radio_if *interf;
-  struct dlep_parser_index idx;
-  int signal;
-  struct netaddr_str nbuf;
-
-  interf = pkt->config.user;
-
-  if (_shutting_down) {
-    /* ignore all UDP communication when shutting down */
-    return;
-  }
-
-  if ((signal = dlep_parser_read(&idx, ptr, length, NULL)) < 0) {
-    OONF_WARN_HEX(LOG_DLEP_RADIO, ptr, length,
-        "Could not parse incoming UDP signal from %s: %d",
-        netaddr_socket_to_string(&nbuf, from), signal);
-    return;
-  }
-
-  OONF_INFO(LOG_DLEP_RADIO, "Received UDP Signal %u from %s",
-      signal, netaddr_socket_to_string(&nbuf, from));
-
-  if (signal != DLEP_PEER_DISCOVERY) {
-    OONF_WARN(LOG_DLEP_RADIO,
-        "Received illegal signal in UDP from %s: %u",
-        netaddr_socket_to_string(&nbuf, from), signal);
-    return;
-  }
-
-  _handle_peer_discovery(interf, from, ptr, &idx);
-}
-
-/**
- * Handle peer discovery signal from UDP
- * @param interface dlep radio interface
- * @param dst IP socket UDP was coming from
- * @param buffer begin of UDP data
- * @param idx index table for DLEP signal
+ * Close all existing dlep sessions of a dlep interface
+ * @param interface dlep router interface
  */
 static void
-_handle_peer_discovery(struct dlep_radio_if *interface,
-    union netaddr_socket *dst, uint8_t *buffer, struct dlep_parser_index *idx) {
-  uint16_t version[2];
-  int pos;
-#ifdef OONF_LOG_INFO
-  struct netaddr_str nbuf;
-#endif
-
-  /* get version */
-  pos = idx->idx[DLEP_VERSION_TLV];
-  dlep_parser_get_version(&version[0], &version[1], &buffer[pos]);
-  if (version[0] == DLEP_VERSION_MAJOR && version[1] < DLEP_VERSION_MINOR) {
-    OONF_WARN(LOG_DLEP_RADIO, "Received peer discovery with version: %u/%u",
-        version[0], version[1]);
-    return;
-  }
-
-  /* create Peer Offer */
-  OONF_INFO(LOG_DLEP_RADIO, "Send UDP Peer Offer to %s",
-      netaddr_socket_to_string(&nbuf, dst));
-
-  _generate_peer_offer(interface, dst);
-}
-
-static void
-_generate_peer_offer(struct dlep_radio_if *interface, union netaddr_socket *dst) {
-  struct netaddr addr;
-
-  dlep_writer_start_signal(DLEP_PEER_OFFER);
-  dlep_writer_add_version_tlv(DLEP_VERSION_MAJOR, DLEP_VERSION_MINOR);
-
-  netaddr_from_socket(&addr, &interface->tcp.socket_v4.local_socket);
-  if (netaddr_get_address_family(&addr) == AF_INET) {
-    dlep_writer_add_ipv4_conpoint_tlv(&addr, interface->tcp_config.port);
-  }
-
-  netaddr_from_socket(&addr, &interface->tcp.socket_v6.local_socket);
-  if (netaddr_get_address_family(&addr) == AF_INET6) {
-    dlep_writer_add_ipv6_conpoint_tlv(&addr, interface->tcp_config.port);
-  }
+_cleanup_interface(struct dlep_radio_if *interface) {
+  struct dlep_radio_session *stream, *it;
 
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    return;
+  /* close TCP connection and socket */
+  avl_for_each_element_safe(&interface->interf.session_tree, stream, _node, it) {
+    dlep_radio_remove_session(stream);
   }
-  dlep_writer_send_udp_unicast(&interface->udp, dst, LOG_DLEP_RADIO);
 }
index 5586cd3..ffb5803 100644 (file)
 #include "common/avl.h"
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_stream_socket.h"
-#include "subsystems/oonf_timer.h"
 
-struct dlep_radio_if {
-  /* interface name to get layer2 data from */
-  char l2_source[IF_NAMESIZE];
+#include "dlep/dlep_session.h"
+#include "dlep/dlep_interface.h"
 
-  /* UDP socket for discovery */
-  struct oonf_packet_managed udp;
-  struct oonf_packet_managed_config udp_config;
+struct dlep_radio_if {
+  struct dlep_if interf;
 
-  /* TCP client socket for session */
+  /* TCP socket for client session */
   struct oonf_stream_managed tcp;
   struct oonf_stream_managed_config tcp_config;
-
-  /* local timer settings */
-  uint64_t local_heartbeat_interval;
-
-  /* decide to publish proxied/non-proxied destinations */
-  bool use_proxied_dst;
-  bool use_nonproxied_dst;
-
-  /* hook into session tree, interface name is the key */
-  struct avl_node _node;
-
-  /* tree of all radio sessions */
-  struct avl_tree session_tree;
 };
 
-struct avl_tree dlep_radio_if_tree;
-
-void dlep_radio_interface_init(void);
+int dlep_radio_interface_init(void);
 void dlep_radio_interface_cleanup(void);
 
-struct dlep_radio_if *dlep_radio_get_interface(const char *ifname);
-struct dlep_radio_if *dlep_radio_add_interface(const char *ifname);
+struct dlep_radio_if *dlep_radio_get_by_layer2_if(const char *ifname);
+struct dlep_radio_if *dlep_radio_add_interface(const char *l2_ifname);
 void dlep_radio_remove_interface(struct dlep_radio_if *);
 
-struct dlep_radio_if *dlep_radio_get_by_source_if(const char *ifname);
+struct dlep_radio_if *dlep_radio_get_by_datapath_if(const char *ifname);
 
 void dlep_radio_apply_interface_settings(struct dlep_radio_if *interface);
 
index 7d65dcb..2aee896 100644 (file)
@@ -50,8 +50,7 @@
 #include "subsystems/oonf_timer.h"
 
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
+#include "dlep/dlep_session.h"
 #include "dlep/dlep_writer.h"
 #include "dlep/radio/dlep_radio.h"
 #include "dlep/radio/dlep_radio_interface.h"
 static int _cb_incoming_tcp(struct oonf_stream_session *);
 static void _cb_tcp_lost(struct oonf_stream_session *);
 static enum oonf_stream_session_state _cb_tcp_receive_data(struct oonf_stream_session *);
+static void _cb_send_buffer(struct dlep_session *session, int af_family);
+static void _cb_end_session(struct dlep_session *session);
 
-static int _handle_peer_initialization(struct dlep_radio_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static int _handle_peer_termination(struct dlep_radio_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static int _handle_peer_termination_ack(struct dlep_radio_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-
-static void _cb_heartbeat_timeout(void *);
-static void _cb_send_heartbeat(void *);
-
-static void _cb_l2_neigh_added(void *);
-static void _cb_l2_neigh_changed(void *);
-static void _cb_l2_neigh_removed(void *);
-
-static void _cb_l2_dst_added(void *);
-static void _cb_l2_dst_removed(void *);
-
-static uint64_t _get_l2neigh_default_value(const struct oonf_layer2_net *l2net,
-    enum oonf_layer2_neighbor_index idx, uint64_t def);
-static uint64_t _get_l2neigh_value(const struct oonf_layer2_neigh *l2neigh,
-    enum oonf_layer2_neighbor_index idx, uint64_t def);
-
-static int _generate_peer_initialization_ack(struct dlep_radio_session *session,
-    const struct oonf_layer2_net *l2net);
-static void _generate_destination_up(struct dlep_radio_session *,
-    const struct oonf_layer2_neigh *, const struct oonf_layer2_destination *l2dst);
-static void _generate_destination_update(struct dlep_radio_session *,
-    const struct oonf_layer2_neigh *, const struct oonf_layer2_destination *l2dst);
-static void _generate_destination_down(struct dlep_radio_session *,
-    const struct oonf_layer2_neigh *, const struct oonf_layer2_destination *l2dst);
-static bool _start_destination_signal(struct dlep_radio_session *session,
-    enum dlep_signals dlep_sig, const char *sig_name,
-    const struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_destination *l2dst);
-
-static struct oonf_class _session_class = {
+static struct oonf_class _radio_session_class = {
   .name = "DLEP TCP session",
   .size = sizeof(struct dlep_radio_session),
 };
 
-static struct oonf_timer_class _heartbeat_timeout_class = {
-  .name = "DLEP radio heartbeat timeout",
-  .callback = _cb_heartbeat_timeout,
-};
-
-static struct oonf_timer_class _heartbeat_timer_class = {
-  .name = "DLEP radio heartbeat",
-  .callback = _cb_send_heartbeat,
-  .periodic = true,
-};
-
-static struct oonf_class_extension _layer2_neigh_listener = {
-  .ext_name = "dlep radio",
-  .class_name = LAYER2_CLASS_NEIGHBOR,
-
-  .cb_add = _cb_l2_neigh_added,
-  .cb_change = _cb_l2_neigh_changed,
-  .cb_remove = _cb_l2_neigh_removed,
-};
-
-static struct oonf_class_extension _layer2_dst_listener = {
-  .ext_name = "dlep radio",
-  .class_name = LAYER2_CLASS_DESTINATION,
-
-  .cb_add = _cb_l2_dst_added,
-  .cb_remove = _cb_l2_dst_removed,
-};
-
 /**
  * Initialize framework for dlep radio sessions
  */
 void
 dlep_radio_session_init(void) {
-  oonf_class_add(&_session_class);
-  oonf_class_extension_add(&_layer2_neigh_listener);
-  oonf_class_extension_add(&_layer2_dst_listener);
-  oonf_timer_add(&_heartbeat_timeout_class);
-  oonf_timer_add(&_heartbeat_timer_class);
+  oonf_class_add(&_radio_session_class);
 }
 
 /**
@@ -146,11 +81,7 @@ dlep_radio_session_init(void) {
  */
 void
 dlep_radio_session_cleanup(void) {
-  oonf_timer_remove(&_heartbeat_timer_class);
-  oonf_timer_remove(&_heartbeat_timeout_class);
-  oonf_class_extension_remove(&_layer2_dst_listener);
-  oonf_class_extension_remove(&_layer2_neigh_listener);
-  oonf_class_remove(&_session_class);
+  oonf_class_remove(&_radio_session_class);
 }
 
 /**
@@ -160,62 +91,23 @@ dlep_radio_session_cleanup(void) {
 void
 dlep_radio_session_initialize_tcp_callbacks(
     struct oonf_stream_config *config) {
-  config->memcookie = &_session_class;
+  config->memcookie = &_radio_session_class;
   config->init = _cb_incoming_tcp;
   config->cleanup = _cb_tcp_lost;
   config->receive_data = _cb_tcp_receive_data;
 }
 
 /**
- * Send peer termination to router
+ * Remove existing dlep radio session
  * @param session dlep radio session
  */
 void
-dlep_radio_terminate_session(struct dlep_radio_session *session) {
-  if (session->state != DLEP_RADIO_SESSION_ACTIVE) {
-    return;
-  }
-
-  dlep_writer_start_signal(DLEP_PEER_TERMINATION);
-  dlep_writer_add_status(DLEP_STATUS_OKAY);
-  if (!dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    dlep_writer_send_tcp_unicast(&session->stream, LOG_DLEP_RADIO);
-
-    session->state = DLEP_RADIO_SESSION_TERMINATE;
+dlep_radio_remove_session(struct dlep_radio_session *radio_session) {
+  if (&radio_session->stream) {
+    oonf_stream_close(&radio_session->stream);
   }
 }
 
-/**
- * Callback to send regular heartbeats over tcp session
- * @param ptr pointer to dlep radio session
- */
-static void
-_cb_send_heartbeat(void *ptr) {
-  struct dlep_radio_session *stream = ptr;
-
-  OONF_DEBUG(LOG_DLEP_RADIO, "Send Heartbeat (%"PRIu64")",
-      stream->interface->local_heartbeat_interval);
-
-  dlep_writer_start_signal(DLEP_HEARTBEAT);
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    return;
-  }
-
-  dlep_writer_send_tcp_unicast(&stream->stream, LOG_DLEP_RADIO);
-}
-
-/**
- * Callback triggered when remote heartbeat times out
- * @param ptr pointer to dlep radio session
- */
-static void
-_cb_heartbeat_timeout(void *ptr) {
-  struct dlep_radio_session *stream = ptr;
-
-  OONF_INFO(LOG_DLEP_RADIO, "Heartbeat timeout");
-  oonf_stream_close(&stream->stream);
-}
-
 /**
  * Callback triggered when a new tcp session is accepted by the local socket
  * @param tcp_session pointer to tcp session object
@@ -223,34 +115,45 @@ _cb_heartbeat_timeout(void *ptr) {
  */
 static int
 _cb_incoming_tcp(struct oonf_stream_session *tcp_session) {
-  struct dlep_radio_session *session;
+  struct dlep_radio_session *radio_session;
   struct dlep_radio_if *interface;
+  struct dlep_extension *ext;
 
-  session = container_of(tcp_session, struct dlep_radio_session, stream);
+  radio_session = container_of(tcp_session, struct dlep_radio_session, stream);
   interface = container_of(tcp_session->comport->managed, struct dlep_radio_if, tcp);
 
   /* initialize back pointer */
-  session->interface = interface;
-
-  /* wait for end of Peer Initialization */
-  session->state = DLEP_RADIO_SESSION_INIT;
+  radio_session->interface = interface;
 
-  /* initialize timer */
-  session->heartbeat_timer.cb_context = session;
-  session->heartbeat_timer.class = &_heartbeat_timer_class;
-
-  session->heartbeat_timeout.cb_context = session;
-  session->heartbeat_timeout.class = &_heartbeat_timeout_class;
-
-  /* start heartbeat timeout */
-  oonf_timer_set(&session->heartbeat_timeout, 2000);
-
-  /* start heartbeat */
-  oonf_timer_set(&session->heartbeat_timer, session->interface->local_heartbeat_interval);
+  /* activate session */
+  if (dlep_session_add(&radio_session->session,
+      interface->interf.l2_ifname, interface->interf.session.l2_origin,
+      &tcp_session->out, true, LOG_DLEP_RADIO)) {
+    return -1;
+  }
+  radio_session->session.next_signal = DLEP_PEER_INITIALIZATION;
+  radio_session->session.cb_send_buffer = _cb_send_buffer;
+  radio_session->session.cb_end_session = _cb_end_session;
+  memcpy(&radio_session->session.cfg, &interface->interf.session.cfg,
+      sizeof(radio_session->session.cfg));
+  memcpy(&radio_session->session.remote_socket, &tcp_session->remote_socket,
+      sizeof(radio_session->session.remote_socket));
 
   /* attach to session tree of interface */
-  session->_node.key = &session->stream.remote_socket;
-  avl_insert(&interface->session_tree, &session->_node);
+  radio_session->_node.key = &radio_session->stream.remote_socket;
+  avl_insert(&interface->interf.session_tree, &radio_session->_node);
+
+  /* copy socket information */
+  memcpy(&radio_session->session.remote_socket,
+      &tcp_session->remote_socket,
+      sizeof(radio_session->session.remote_socket));
+
+  /* inform all extensions */
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (ext->cb_session_init_radio) {
+      ext->cb_session_init_radio(&radio_session->session);
+    }
+  }
 
   return 0;
 }
@@ -261,109 +164,29 @@ _cb_incoming_tcp(struct oonf_stream_session *tcp_session) {
  */
 static void
 _cb_tcp_lost(struct oonf_stream_session *tcp_session) {
-  struct dlep_radio_session *session;
-  struct dlep_radio_if *interface;
+  struct dlep_radio_session *radio_session;
+  struct dlep_extension *ext;
 #ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str nbuf;
 #endif
 
-  session = container_of(tcp_session, struct dlep_radio_session, stream);
-  interface = container_of(tcp_session->comport->managed, struct dlep_radio_if, tcp);
+  radio_session = container_of(tcp_session, struct dlep_radio_session, stream);
 
   OONF_DEBUG(LOG_DLEP_RADIO, "Lost tcp session to %s",
       netaddr_socket_to_string(&nbuf, &tcp_session->remote_socket));
 
-  /* reset timers */
-  oonf_timer_stop(&session->heartbeat_timer);
-  oonf_timer_stop(&session->heartbeat_timeout);
-
-  /* remove from session tree of interface */
-  avl_remove(&interface->session_tree, &session->_node);
-}
-
-/**
- *
- * @param tcp_session
- * @param session
- * @return -1 if an error happened, 1 if buffer needs more bytes
- *  for a signal, 0 if signal was parsed
- */
-static int
-_parse_signal(struct oonf_stream_session *tcp_session,
-    struct dlep_radio_session *session) {
-  struct dlep_parser_index idx;
-  uint16_t siglen;
-  int signal, result;
-  struct netaddr_str nbuf;
-
-  if ((signal = dlep_parser_read(&idx, abuf_getptr(&tcp_session->in),
-      abuf_getlen(&tcp_session->in), &siglen)) < 0) {
-    if (signal != DLEP_PARSER_INCOMPLETE_HEADER
-        && signal != DLEP_PARSER_INCOMPLETE_SIGNAL) {
-      OONF_WARN_HEX(LOG_DLEP_RADIO,
-          abuf_getptr(&tcp_session->in), abuf_getlen(&tcp_session->in),
-          "Could not parse incoming TCP signal from %s: %d",
-          netaddr_to_string(&nbuf, &tcp_session->remote_address), signal);
-
-      return -1;
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (ext->cb_session_cleanup_radio) {
+      ext->cb_session_cleanup_radio(&radio_session->session);
     }
-    return 0;
-  }
-
-  if (session->state == DLEP_RADIO_SESSION_INIT
-      && signal != DLEP_PEER_INITIALIZATION) {
-    OONF_WARN(LOG_DLEP_RADIO,
-        "Received TCP signal %d before Peer Initialization", signal);
-    return -1;
   }
 
-  if (session->state == DLEP_RADIO_SESSION_TERMINATE
-      && signal != DLEP_PEER_TERMINATION_ACK) {
-    OONF_DEBUG(LOG_DLEP_RADIO,
-        "Ignore signal %d when waiting for Termination Ack", signal);
+  /* kill embedded session object */
+  dlep_session_remove(&radio_session->session);
 
-    /* remove signal from input buffer */
-    abuf_pull(&tcp_session->in, siglen);
-
-    return 1;
-  }
-
-  OONF_INFO(LOG_DLEP_RADIO, "Received TCP signal %d", signal);
-
-  result = 0;
-  switch (signal) {
-    case DLEP_PEER_INITIALIZATION:
-      result = _handle_peer_initialization(
-          session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_HEARTBEAT:
-      OONF_DEBUG(LOG_DLEP_RADIO, "Received TCP heartbeat, reset interval to %"PRIu64,
-          session->remote_heartbeat_interval * 2);
-      oonf_timer_set(&session->heartbeat_timeout, session->remote_heartbeat_interval * 2);
-      break;
-    case DLEP_PEER_TERMINATION:
-      result = _handle_peer_termination(
-          session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_PEER_TERMINATION_ACK:
-      result = _handle_peer_termination_ack(
-          session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_DESTINATION_UP_ACK:
-      break;
-    case DLEP_DESTINATION_DOWN_ACK:
-      break;
-    default:
-      OONF_WARN(LOG_DLEP_RADIO,
-          "Received illegal signal in TCP from %s: %u",
-          netaddr_to_string(&nbuf, &tcp_session->remote_address), signal);
-      return -1;
-  }
-
-  /* remove signal from input buffer */
-  abuf_pull(&tcp_session->in, siglen);
-
-  return result != 0 ? -1 : 1;
+  /* remove from session tree of interface */
+  avl_remove(&radio_session->interface->interf.session_tree,
+      &radio_session->_node);
 }
 
 /**
@@ -373,526 +196,37 @@ _parse_signal(struct oonf_stream_session *tcp_session,
  */
 static enum oonf_stream_session_state
 _cb_tcp_receive_data(struct oonf_stream_session *tcp_session) {
-  struct dlep_radio_session *session;
-  int result;
-
-  session = container_of(tcp_session, struct dlep_radio_session, stream);
-
-  while ((result = _parse_signal(tcp_session, session)) == 1);
-
-  return result == -1 ? STREAM_SESSION_CLEANUP :STREAM_SESSION_ACTIVE;
-}
-
-/**
- * Handle peer initialization from router
- * @param session dlep radio session
- * @param ptr pointer to begin of signal
- * @param idx dlep parser index
- * @return -1 if an error happened, 0 otherwise
- */
-static int
-_handle_peer_initialization(struct dlep_radio_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  struct oonf_layer2_destination *l2dst;
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_net *l2net;
-  uint8_t *buffer;
-  char peer[256];
-  int pos;
-  uint16_t version[2];
-  buffer = ptr;
-
-  /* get version */
-  pos = idx->idx[DLEP_VERSION_TLV];
-  dlep_parser_get_version(&version[0], &version[1], &buffer[pos]);
-  if (version[0] == DLEP_VERSION_MAJOR && version[1] < DLEP_VERSION_MINOR) {
-    OONF_WARN(LOG_DLEP_RADIO, "Received peer discovery with version: %u/%u",
-        version[0], version[1]);
-    return -1;
-  }
-
-  /* get peer type */
-  peer[0] = 0;
-  pos = idx->idx[DLEP_PEER_TYPE_TLV];
-  if (pos) {
-    dlep_parser_get_peer_type(peer, &buffer[pos]);
-
-    OONF_INFO(LOG_DLEP_RADIO, "Router peer type: %s", peer);
-  }
-
-  /* get reference to l2 network data */
-  l2net = oonf_layer2_net_add(session->interface->l2_source);
-  if (!l2net) {
-    return -1;
-  }
-
-  /* get heartbeat interval */
-  pos = idx->idx[DLEP_HEARTBEAT_INTERVAL_TLV];
-  dlep_parser_get_heartbeat_interval(
-      &session->remote_heartbeat_interval, &buffer[pos]);
-
-  /* reset heartbeat timeout */
-  oonf_timer_set(&session->heartbeat_timeout, session->remote_heartbeat_interval);
-
-  if (_generate_peer_initialization_ack(session, l2net)) {
-    return -1;
-  }
-
-  /* activate session */
-  session->state = DLEP_RADIO_SESSION_ACTIVE;
-
-  /* generate Destination Up for all active neighbors */
-  avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
-    _generate_destination_up(session, l2neigh, NULL);
-
-    avl_for_each_element(&l2neigh->destinations, l2dst, _node) {
-      _generate_destination_up(session, l2neigh, l2dst);
-    }
-  }
-  return 0;
-}
-
-/**
- * Handle peer termination from router
- * @param session dlep radio session
- * @param ptr pointer to begin of signal
- * @param idx dlep parser index
- * @return -1 if an error happened, 0 otherwise
- */
-static int
-_handle_peer_termination(struct dlep_radio_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  uint8_t *buffer = ptr;
-  enum dlep_status status;
-  int pos;
-
-  pos = idx->idx[DLEP_STATUS_TLV];
-  if (pos) {
-    dlep_parser_get_status(&status, &buffer[pos]);
-    OONF_DEBUG(LOG_DLEP_RADIO, "Peer termination status: %u",
-        status);
-  }
-
-  /* send Peer Termination Ack */
-  dlep_writer_start_signal(DLEP_PEER_TERMINATION_ACK);
-  dlep_writer_add_status(DLEP_STATUS_OKAY);
-
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    return -1;
-  }
-
-  dlep_writer_send_tcp_unicast(&session->stream, LOG_DLEP_RADIO);
-  return 0;
-}
-
-/**
- * Handle peer termination ack from router
- * @param session dlep radio session
- * @param ptr pointer to begin of signal
- * @param idx dlep parser index
- * @return -1 if an error happened, 0 otherwise
- */
-static int
-_handle_peer_termination_ack(struct dlep_radio_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  uint8_t *buffer = ptr;
-  enum dlep_status status;
-  int pos;
-  struct netaddr_str nbuf;
-
-  pos = idx->idx[DLEP_STATUS_TLV];
-  if (pos) {
-    dlep_parser_get_status(&status, &buffer[pos]);
-    OONF_DEBUG(LOG_DLEP_RADIO, "Peer termination ack status: %u",
-        status);
-  }
-
-  if (session->state != DLEP_RADIO_SESSION_TERMINATE) {
-    OONF_WARN(LOG_DLEP_RADIO, "Got Peer Termination ACK without"
-        " sending a Peer Terminate from %s",
-        netaddr_socket_to_string(&nbuf, &session->stream.remote_socket));
-  }
-
-  /* terminate session */
-  return -1;
-}
-
-static void
-_cb_l2_neigh_added(void *ptr) {
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_net *l2net;
-  struct dlep_radio_if *dlep_if;
-  struct dlep_radio_session *dlep_session;
-
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf1;
-#endif
-
-  /* get l2neighbor and l2network */
-  l2neigh = ptr;
-  l2net = l2neigh->network;
-
-  dlep_if = dlep_radio_get_by_source_if(l2net->name);
-  if (!dlep_if) {
-    /* this is not a dlep source */
-    return;
-  }
-
-  OONF_DEBUG(LOG_DLEP_RADIO, "Received neighbor addition for %s on interface %s",
-      netaddr_to_string(&nbuf1, &l2neigh->addr), l2net->name);
-
-  avl_for_each_element(&dlep_if->session_tree, dlep_session, _node) {
-    if (dlep_session->state == DLEP_RADIO_SESSION_ACTIVE) {
-      _generate_destination_up(dlep_session, l2neigh, NULL);
-    }
-  }
-}
-
-static void
-_cb_l2_neigh_changed(void *ptr) {
-  struct oonf_layer2_destination *l2dst;
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_net *l2net;
-  struct dlep_radio_if *dlep_if;
-  struct dlep_radio_session *dlep_session;
-
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf1;
-#endif
-
-  /* get l2neighbor and l2network */
-  l2neigh = ptr;
-  l2net = l2neigh->network;
-
-  dlep_if = dlep_radio_get_by_source_if(l2net->name);
-  if (!dlep_if) {
-    OONF_DEBUG(LOG_DLEP_RADIO, "Received neighbor change for %s on interface %s: no dlep interface",
-          netaddr_to_string(&nbuf1, &l2neigh->addr), l2net->name);
-    /* this is not a dlep source */
-    return;
-  }
-
-  OONF_DEBUG(LOG_DLEP_RADIO, "Received neighbor change for %s on interface %s",
-      netaddr_to_string(&nbuf1, &l2neigh->addr), l2net->name);
-
-  avl_for_each_element(&dlep_if->session_tree, dlep_session, _node) {
-    if (dlep_session->state == DLEP_RADIO_SESSION_ACTIVE) {
-      if (dlep_if->use_nonproxied_dst) {
-        OONF_DEBUG(LOG_DLEP_RADIO, "Handle non-proxied change");
-        _generate_destination_update(dlep_session, l2neigh, NULL);
-      }
-
-      if (dlep_if->use_proxied_dst) {
-        OONF_DEBUG(LOG_DLEP_RADIO, "Handle proxied changes");
-        avl_for_each_element(&l2neigh->destinations, l2dst, _node) {
-          OONF_DEBUG(LOG_DLEP_RADIO, "Handle non-proxied change for %s",
-              netaddr_to_string(&nbuf1, &l2dst->destination));
-          _generate_destination_update(dlep_session, l2neigh, l2dst);
-        }
-      }
-    }
-  }
-}
-
-static void
-_cb_l2_neigh_removed(void *ptr) {
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_net *l2net;
-  struct dlep_radio_if *dlep_if;
-  struct dlep_radio_session *dlep_session;
-
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf1;
-#endif
-
-  /* get l2neighbor and l2network */
-  l2neigh = ptr;
-  l2net = l2neigh->network;
-
-  dlep_if = dlep_radio_get_by_source_if(l2net->name);
-  if (!dlep_if) {
-    /* this is not a dlep source */
-    return;
-  }
-
-  OONF_DEBUG(LOG_DLEP_RADIO, "Received neighbor removal for %s on interface %s",
-      netaddr_to_string(&nbuf1, &l2neigh->addr), l2net->name);
-
-  avl_for_each_element(&dlep_if->session_tree, dlep_session, _node) {
-    if (dlep_session->state == DLEP_RADIO_SESSION_ACTIVE) {
-      _generate_destination_down(dlep_session, l2neigh, NULL);
-    }
-  }
-}
-
-static void
-_cb_l2_dst_added(void *ptr) {
-  struct oonf_layer2_destination *l2dst;
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_net *l2net;
-  struct dlep_radio_if *dlep_if;
-  struct dlep_radio_session *dlep_session;
-
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf1, nbuf2;
-#endif
-
-  /* get l2neighbor and l2network */
-  l2dst = ptr;
-  l2neigh = l2dst->neighbor;
-  l2net = l2neigh->network;
-
-  dlep_if = dlep_radio_get_by_source_if(l2net->name);
-  if (!dlep_if) {
-    /* this is not a dlep source */
-    return;
-  }
-
-  OONF_DEBUG(LOG_DLEP_RADIO, "Received neighbor addition for %s (%s) on interface %s",
-      netaddr_to_string(&nbuf1, &l2dst->destination),
-      netaddr_to_string(&nbuf2, &l2neigh->addr), l2net->name);
-
-  avl_for_each_element(&dlep_if->session_tree, dlep_session, _node) {
-    if (dlep_session->state == DLEP_RADIO_SESSION_ACTIVE) {
-      _generate_destination_up(dlep_session, l2neigh, l2dst);
-    }
-  }
-}
-
-static void
-_cb_l2_dst_removed(void *ptr) {
-  struct oonf_layer2_destination *l2dst;
-  struct oonf_layer2_neigh *l2neigh;
-  struct oonf_layer2_net *l2net;
-  struct dlep_radio_if *dlep_if;
-  struct dlep_radio_session *dlep_session;
-
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf1, nbuf2;
-#endif
-
-  /* get l2neighbor and l2network */
-  l2dst = ptr;
-  l2neigh = l2dst->neighbor;
-  l2net = l2neigh->network;
-
-  dlep_if = dlep_radio_get_by_source_if(l2net->name);
-  if (!dlep_if) {
-    /* this is not a dlep source */
-    return;
-  }
-
-  OONF_DEBUG(LOG_DLEP_RADIO, "Received neighbor removal for %s (%s) on interface %s",
-      netaddr_to_string(&nbuf1, &l2dst->destination),
-      netaddr_to_string(&nbuf2, &l2neigh->addr), l2net->name);
-
-  avl_for_each_element(&dlep_if->session_tree, dlep_session, _node) {
-    if (dlep_session->state == DLEP_RADIO_SESSION_ACTIVE) {
-      _generate_destination_down(dlep_session, l2neigh, l2dst);
-    }
-  }
-}
+  struct dlep_radio_session *radio_session;
 
-static uint64_t
-_get_l2neigh_default_value(const struct oonf_layer2_net *l2net,
-    enum oonf_layer2_neighbor_index idx, uint64_t def) {
-  const struct oonf_layer2_data *data;
+  radio_session = container_of(tcp_session, struct dlep_radio_session, stream);
 
-  if (!l2net) {
-    return def;
-  }
-
-  data = &l2net->neighdata[idx];
-  if (oonf_layer2_has_value(data)) {
-    return oonf_layer2_get_value(data);
-  }
-  else {
-    return def;
-  }
-}
-
-static uint64_t
-_get_l2neigh_value(const struct oonf_layer2_neigh *l2neigh,
-    enum oonf_layer2_neighbor_index idx, uint64_t def) {
-  const struct oonf_layer2_data *data;
-
-  if (!l2neigh) {
-    return def;
-  }
-
-  data = oonf_layer2_neigh_get_value(l2neigh, idx);
-  if (data) {
-    return oonf_layer2_get_value(data);
-  }
-  else {
-    return def;
-  }
-}
-
-static void
-_handle_uint64_metric(const struct oonf_layer2_net *l2net,
-    const struct oonf_layer2_neigh *l2neigh,
-    enum oonf_layer2_neighbor_index l2type, enum dlep_tlvs dleptlv) {
-  if (l2net) {
-    dlep_writer_add_uint64(
-        _get_l2neigh_default_value(l2net, l2type, 0), dleptlv);
-  }
-  else {
-    dlep_writer_add_uint64(
-        _get_l2neigh_value(l2neigh, l2type, 0), dleptlv);
-  }
-}
-
-static void
-_handle_metrics(const struct oonf_layer2_net *l2net,
-    const struct oonf_layer2_neigh *l2neigh) {
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_RX_MAX_BITRATE, DLEP_MDRR_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_TX_MAX_BITRATE, DLEP_MDRT_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_RX_BITRATE, DLEP_CDRR_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_TX_BITRATE, DLEP_CDRT_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_RX_FRAMES, DLEP_FRAMES_R_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_TX_FRAMES, DLEP_FRAMES_T_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_RX_BYTES, DLEP_BYTES_R_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_TX_BYTES, DLEP_BYTES_T_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_TX_RETRIES, DLEP_FRAMES_RETRIES_TLV);
-  _handle_uint64_metric(l2net, l2neigh,
-      OONF_LAYER2_NEIGH_TX_FAILED, DLEP_FRAMES_FAILED_TLV);
-
-  if (l2net) {
-    dlep_writer_add_tx_signal(
-        _get_l2neigh_default_value(l2net, OONF_LAYER2_NEIGH_TX_SIGNAL, 0));
-    dlep_writer_add_rx_signal(
-        _get_l2neigh_default_value(l2net, OONF_LAYER2_NEIGH_RX_SIGNAL, 0));
-  }
-  else {
-    dlep_writer_add_tx_signal(
-        _get_l2neigh_value(l2neigh, OONF_LAYER2_NEIGH_TX_SIGNAL, 0));
-    dlep_writer_add_rx_signal(
-        _get_l2neigh_value(l2neigh, OONF_LAYER2_NEIGH_RX_SIGNAL, 0));
-  }
-}
-
-static int
-_generate_peer_initialization_ack(struct dlep_radio_session *session,
-    const struct oonf_layer2_net *l2net) {
-  /* create PEER initialization ACK */
-  dlep_writer_start_signal(DLEP_PEER_INITIALIZATION_ACK);
-
-  /* add mandatory TLVs */
-  dlep_writer_add_heartbeat_tlv(session->interface->local_heartbeat_interval);
-  dlep_writer_add_version_tlv(DLEP_VERSION_MAJOR, DLEP_VERSION_MINOR);
-
-  /* add metrics */
-  _handle_metrics(l2net, NULL);
-
-  /* report a fixed latency because we cannot measure it */
-  dlep_writer_add_latency(1000);
-
-  /* assemble signal */
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    return -1;
-  }
-
-  /* send signal */
-  dlep_writer_send_tcp_unicast(&session->stream, LOG_DLEP_RADIO);
-
-  return 0;
+  return dlep_session_process_tcp(tcp_session, &radio_session->session);
 }
 
 static void
-_generate_destination_up(struct dlep_radio_session *session,
-    const struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_destination *l2dst) {
-  if (!_start_destination_signal(
-      session, DLEP_DESTINATION_UP, "up", l2neigh, l2dst)) {
-    return;
-  }
-
-  _handle_metrics(NULL, l2neigh);
-
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    dlep_radio_terminate_session(session);
-    return;
-  }
+_cb_send_buffer(struct dlep_session *session,
+    int af_family __attribute((unused))) {
+  struct dlep_radio_session *radio_session;
 
-  dlep_writer_send_tcp_unicast(&session->stream, LOG_DLEP_RADIO);
-}
-
-static void
-_generate_destination_update(struct dlep_radio_session *session,
-    const struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_destination *l2dst) {
-  if (!_start_destination_signal(
-      session, DLEP_DESTINATION_UPDATE, "update", l2neigh, l2dst)) {
+  if (!abuf_getlen(session->writer.out)) {
     return;
   }
 
-  _handle_metrics(NULL, l2neigh);
+  OONF_DEBUG(session->log_source, "Send buffer %" PRIu64 " bytes",
+      abuf_getlen(session->writer.out));
 
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    dlep_radio_terminate_session(session);
-    return;
-  }
+  /* get pointer to radio interface */
+  radio_session = container_of(session, struct dlep_radio_session, session);
 
-  dlep_writer_send_tcp_unicast(&session->stream, LOG_DLEP_RADIO);
+  oonf_stream_flush(&radio_session->stream);
 }
 
 static void
-_generate_destination_down(struct dlep_radio_session *session,
-    const struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_destination *l2dst) {
-  if (!_start_destination_signal(
-      session, DLEP_DESTINATION_DOWN, "down", l2neigh, l2dst)) {
-    return;
-  }
+_cb_end_session(struct dlep_session *session) {
+  struct dlep_radio_session *radio_session;
 
-  if (dlep_writer_finish_signal(LOG_DLEP_RADIO)) {
-    dlep_radio_terminate_session(session);
-    return;
-  }
-
-  dlep_writer_send_tcp_unicast(&session->stream, LOG_DLEP_RADIO);
-}
-
-static bool
-_start_destination_signal(struct dlep_radio_session *session,
-    enum dlep_signals dlep_sig, const char *sig_name __attribute__((unused)),
-    const struct oonf_layer2_neigh *l2neigh, const struct oonf_layer2_destination *l2dst) {
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf1, nbuf2;
-#endif
-  /* test if we should send signal */
-  if (l2dst) {
-    if (!session->interface->use_proxied_dst) {
-      return false;
-    }
+  /* get pointer to radio interface */
+  radio_session = container_of(session, struct dlep_radio_session, session);
 
-    OONF_DEBUG(LOG_DLEP_RADIO, "Destination %s: %s %s/%s",
-        sig_name, l2neigh->network->name, netaddr_to_string(&nbuf1, &l2neigh->addr),
-        netaddr_to_string(&nbuf2, &l2dst->destination));
-  }
-  else {
-    if (!session->interface->use_nonproxied_dst) {
-      return false;
-    }
-
-    OONF_DEBUG(LOG_DLEP_RADIO, "Destination %s: %s %s",
-        sig_name, l2neigh->network->name, netaddr_to_string(&nbuf1, &l2neigh->addr));
-  }
-
-  dlep_writer_start_signal(dlep_sig);
-
-  if (l2dst) {
-    dlep_writer_add_mac_tlv(&l2dst->destination);
-  }
-  else {
-    dlep_writer_add_mac_tlv(&l2neigh->addr);
-  }
-  return true;
+  dlep_radio_remove_session(radio_session);
 }
index 77a6143..7e1eab9 100644 (file)
 #include "subsystems/oonf_stream_socket.h"
 #include "subsystems/oonf_timer.h"
 
+#include "dlep/dlep_session.h"
 #include "dlep/radio/dlep_radio_session.h"
 
-enum dlep_radio_session_state {
-  DLEP_RADIO_SESSION_INIT,
-  DLEP_RADIO_SESSION_ACTIVE,
-  DLEP_RADIO_SESSION_TERMINATE,
-};
-
 struct dlep_radio_session {
   /* basic content for tcp stream */
   struct oonf_stream_session stream;
 
+  /* generic DLEP session */
+  struct dlep_session session;
+
   /* back pointer to interface session */
   struct dlep_radio_if *interface;
 
-  /* state of the DLEP session */
-  enum dlep_radio_session_state state;
-
-  /* heartbeat timer */
-  struct oonf_timer_instance heartbeat_timer;
-
-  /* heartbeat timeout */
-  struct oonf_timer_instance heartbeat_timeout;
-
-  /* heartbeat settings from the other side of the session */
-  uint64_t remote_heartbeat_interval;
-
   /* node for session tree of interface */
   struct avl_node _node;
 };
@@ -83,8 +69,8 @@ struct dlep_radio_session {
 void dlep_radio_session_init(void);
 void dlep_radio_session_cleanup(void);
 
+void dlep_radio_remove_session(struct dlep_radio_session *router_session);
 void dlep_radio_session_initialize_tcp_callbacks(
     struct oonf_stream_config *config);
 
-void dlep_radio_terminate_session(struct dlep_radio_session *session);
 #endif /* DLEP_RADIO_SESSION_H_ */
index 01d44ca..981381c 100644 (file)
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_layer2.h"
+#include "subsystems/oonf_stream_socket.h"
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_timer.h"
 
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
-#include "dlep/dlep_writer.h"
+#include "dlep/dlep_session.h"
 #include "dlep/router/dlep_router.h"
 #include "dlep/router/dlep_router_interface.h"
 
@@ -71,27 +70,27 @@ static void _cb_config_changed(void);
 
 /* configuration */
 static struct cfg_schema_entry _router_entries[] = {
-  CFG_MAP_NETADDR_V4(dlep_router_if, udp_config.multicast_v4, "discovery_mc_v4",
+  CFG_MAP_NETADDR_V4(dlep_router_if, interf.udp_config.multicast_v4, "discovery_mc_v4",
     DLEP_WELL_KNOWN_MULTICAST_ADDRESS, "IPv4 address to send discovery UDP packet to", false, false),
-  CFG_MAP_NETADDR_V6(dlep_router_if, udp_config.multicast_v6, "discovery_mc_v6",
+  CFG_MAP_NETADDR_V6(dlep_router_if, interf.udp_config.multicast_v6, "discovery_mc_v6",
     DLEP_WELL_KNOWN_MULTICAST_ADDRESS_6, "IPv6 address to send discovery UDP packet to", false, false),
-  CFG_MAP_INT32_MINMAX(dlep_router_if, udp_config.multicast_port, "discovery_port",
+  CFG_MAP_INT32_MINMAX(dlep_router_if, interf.udp_config.multicast_port, "discovery_port",
     DLEP_WELL_KNOWN_MULTICAST_PORT_TXT, "UDP port for discovery packets", 0, false, 1, 65535),
 
-  CFG_MAP_ACL_V46(dlep_router_if, udp_config.bindto, "discovery_bindto", "fe80::/10",
+  CFG_MAP_ACL_V46(dlep_router_if, interf.udp_config.bindto, "discovery_bindto", "fe80::/10",
     "Filter to determine the binding of the UDP discovery socket"),
 
-  CFG_MAP_CLOCK_MIN(dlep_router_if, local_discovery_interval,
+  CFG_MAP_CLOCK_MIN(dlep_router_if, interf.session.cfg.discovery_interval,
     "discovery_interval", "1.000",
     "Interval in seconds between two discovery beacons", 1000),
-  CFG_MAP_CLOCK_MINMAX(dlep_router_if, local_heartbeat_interval,
+  CFG_MAP_CLOCK_MINMAX(dlep_router_if, interf.session.cfg.heartbeat_interval,
       "heartbeat_interval", "1.000",
     "Interval in seconds between two heartbeat signals", 1000, 65535000),
 
-  CFG_MAP_BOOL(dlep_router_if, single_session, "single_session", "true",
+  CFG_MAP_BOOL(dlep_router_if, interf.single_session, "single_session", "true",
       "Restrict DLEP router to single session per interface"),
 
-  CFG_MAP_STRING_ARRAY(dlep_router_if, udp_config.interface, "datapath_if", "",
+  CFG_MAP_STRING_ARRAY(dlep_router_if, interf.udp_config.interface, "datapath_if", "",
       "Overwrite datapath interface for incoming dlep traffic, used for"
       " receiving DLEP data through out-of-band channel.", IF_NAMESIZE),
 };
@@ -145,10 +144,6 @@ _early_cfg_init(void) {
  */
 static int
 _init(void) {
-  if (dlep_writer_init()) {
-    return -1;
-  }
-
   dlep_router_interface_init();
   return 0;
 }
@@ -167,7 +162,6 @@ _initiate_shutdown(void) {
 static void
 _cleanup(void) {
   dlep_router_interface_cleanup();
-  dlep_writer_cleanup();
 }
 
 /**
@@ -179,7 +173,7 @@ _cb_config_changed(void) {
 
   if (!_router_section.post) {
     /* remove old session object */
-    interface = dlep_router_get_interface(_router_section.section_name);
+    interface = dlep_router_get_by_layer2_if(_router_section.section_name);
     if (interface) {
       dlep_router_remove_interface(interface);
     }
@@ -201,9 +195,10 @@ _cb_config_changed(void) {
   }
 
   /* use section name as default for datapath interface */
-  if (!interface->udp_config.interface[0]) {
-    strscpy(interface->udp_config.interface, _router_section.section_name,
-        sizeof(interface->udp_config.interface));
+  if (!interface->interf.udp_config.interface[0]) {
+    strscpy(interface->interf.udp_config.interface,
+        _router_section.section_name,
+        sizeof(interface->interf.udp_config.interface));
   }
 
   /* apply settings */
index 8875ff2..7db092e 100644 (file)
 #include "subsystems/oonf_packet_socket.h"
 #include "subsystems/oonf_timer.h"
 
+#include "dlep/dlep_extension.h"
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
+#include "dlep/dlep_interface.h"
+#include "dlep/dlep_session.h"
 #include "dlep/dlep_writer.h"
+#include "dlep/dlep_base/dlep_base_router.h"
 #include "dlep/router/dlep_router.h"
 #include "dlep/router/dlep_router_interface.h"
 #include "dlep/router/dlep_router_internal.h"
 #include "dlep/router/dlep_router_session.h"
 
 static void _cleanup_interface(struct dlep_router_if *interface);
-static void _cb_send_discovery(void *);
-
-static void _cb_receive_udp(struct oonf_packet_socket *,
-    union netaddr_socket *from, void *ptr, size_t length);
-static void _handle_peer_offer(struct dlep_router_if *interface,
-    uint8_t *buffer, size_t length, struct dlep_parser_index *idx);
-
-static void _generate_peer_discovery(struct dlep_router_if *interface);
 
 static struct avl_tree _interface_tree;
 
@@ -78,13 +72,8 @@ static struct oonf_class _router_if_class = {
   .size = sizeof(struct dlep_router_if),
 };
 
-static struct oonf_timer_class _discovery_timer_class = {
-  .name = "DLEP router heartbeat",
-  .callback = _cb_send_discovery,
-  .periodic = true,
-};
-
 static bool _shutting_down;
+uint32_t _l2_origin;
 
 /**
  * Initialize dlep router interface framework. This will also
@@ -93,12 +82,16 @@ static bool _shutting_down;
 void
 dlep_router_interface_init(void) {
   oonf_class_add(&_router_if_class);
-  oonf_timer_add(&_discovery_timer_class);
   avl_init(&_interface_tree, avl_comp_strcasecmp, false);
 
+  dlep_extension_init();
+  dlep_session_init();
   dlep_router_session_init();
+  dlep_base_router_init();
 
   _shutting_down = false;
+
+  _l2_origin = oonf_layer2_register_origin();
 }
 
 /**
@@ -109,26 +102,42 @@ void
 dlep_router_interface_cleanup(void) {
   struct dlep_router_if *interf, *it;
 
-  avl_for_each_element_safe(&_interface_tree, interf, _node, it) {
+  avl_for_each_element_safe(&_interface_tree, interf, interf._node, it) {
     dlep_router_remove_interface(interf);
   }
 
-  oonf_timer_remove(&_discovery_timer_class);
   oonf_class_remove(&_router_if_class);
 
   dlep_router_session_cleanup();
 }
 
 /**
- * Get a dlep router interface via interface name
+ * Get a dlep router interface by layer2 interface name
+ * @param l2_ifname interface name
+ * @return dlep router interface, NULL if not found
+ */
+struct dlep_router_if *
+dlep_router_get_by_layer2_if(const char *l2_ifname) {
+  struct dlep_router_if *interf;
+
+  return avl_find_element(&_interface_tree, l2_ifname, interf, interf._node);
+}
+
+/**
+ * Get a dlep router interface by dlep datapath name
  * @param ifname interface name
  * @return dlep router interface, NULL if not found
  */
 struct dlep_router_if *
-dlep_router_get_interface(const char *ifname) {
-  struct dlep_router_if *interface;
+dlep_router_get_by_datapath_if(const char *ifname) {
+  struct dlep_router_if *interf;
 
-  return avl_find_element(&_interface_tree, ifname, interface, _node);
+  avl_for_each_element(&_interface_tree, interf, interf._node) {
+    if (strcmp(interf->interf.udp_config.interface, ifname) == 0) {
+      return interf;
+    }
+  }
+  return NULL;
 }
 
 /**
@@ -140,10 +149,9 @@ struct dlep_router_if *
 dlep_router_add_interface(const char *ifname) {
   struct dlep_router_if *interface;
 
-  OONF_DEBUG(LOG_DLEP_ROUTER, "Add session %s", ifname);
-
-  interface = dlep_router_get_interface(ifname);
+  interface = dlep_router_get_by_layer2_if(ifname);
   if (interface) {
+    OONF_DEBUG(LOG_DLEP_ROUTER, "use existing instance for %s", ifname);
     return interface;
   }
 
@@ -152,24 +160,16 @@ dlep_router_add_interface(const char *ifname) {
     return NULL;
   }
 
-  /* initialize key */
-  strscpy(interface->l2_destination, ifname, sizeof(interface->l2_destination));
-  interface->_node.key = interface->l2_destination;
-
-  /* initialize timer */
-  interface->discovery_timer.cb_context = interface;
-  interface->discovery_timer.class = &_discovery_timer_class;
+  if (dlep_if_add(&interface->interf, ifname,
+      _l2_origin, LOG_DLEP_ROUTER, false)) {
+    oonf_class_free(&_router_if_class, interface);
+    return NULL;
+  }
 
   /* add to global tree of sessions */
-  avl_insert(&_interface_tree, &interface->_node);
-
-  /* initialize discovery socket */
-  interface->udp.config.user = interface;
-  interface->udp.config.receive_data = _cb_receive_udp;
-  oonf_packet_add_managed(&interface->udp);
+  avl_insert(&_interface_tree, &interface->interf._node);
 
-  /* initialize stream list */
-  avl_init(&interface->session_tree, avl_comp_netaddr_socket, false);
+  OONF_DEBUG(LOG_DLEP_ROUTER, "Add session %s", ifname);
 
   return interface;
 }
@@ -180,18 +180,14 @@ dlep_router_add_interface(const char *ifname) {
  */
 void
 dlep_router_remove_interface(struct dlep_router_if *interface) {
-  OONF_DEBUG(LOG_DLEP_ROUTER, "remove session %s", interface->l2_destination);
-
+  /* close all sessions */
   _cleanup_interface(interface);
 
-  /* close UDP interface */
-  oonf_packet_remove_managed(&interface->udp, true);
-
-  /* stop timers */
-  oonf_timer_stop(&interface->discovery_timer);
+  /* cleanup generic interface */
+  dlep_if_remove(&interface->interf);
 
   /* remove session */
-  avl_remove(&_interface_tree, &interface->_node);
+  avl_remove(&_interface_tree, &interface->interf._node);
   oonf_class_free(&_router_if_class, interface);
 }
 
@@ -202,12 +198,16 @@ dlep_router_remove_interface(struct dlep_router_if *interface) {
  */
 void
 dlep_router_apply_interface_settings(struct dlep_router_if *interf) {
-  oonf_packet_apply_managed(&interf->udp, &interf->udp_config);
+  struct dlep_extension *ext;
+  oonf_packet_apply_managed(&interf->interf.udp, &interf->interf.udp_config);
 
   _cleanup_interface(interf);
 
-  /* reset discovery timers */
-  oonf_timer_set(&interf->discovery_timer, interf->local_discovery_interval);
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (ext->cb_session_apply_router) {
+      ext->cb_session_apply_router(&interf->interf.session);
+    }
+  }
 }
 
 /**
@@ -216,13 +216,13 @@ dlep_router_apply_interface_settings(struct dlep_router_if *interf) {
 void
 dlep_router_terminate_all_sessions(void) {
   struct dlep_router_if *interf;
-  struct dlep_router_session *session;
+  struct dlep_router_session *router_session;
 
   _shutting_down = true;
 
-  avl_for_each_element(&_interface_tree, interf, _node) {
-    avl_for_each_element(&interf->session_tree, session, _node) {
-      dlep_router_terminate_session(session);
+  avl_for_each_element(&_interface_tree, interf, interf._node) {
+    avl_for_each_element(&interf->interf.session_tree, router_session, _node) {
+      dlep_session_terminate(&router_session->session);
     }
   }
 }
@@ -236,216 +236,7 @@ _cleanup_interface(struct dlep_router_if *interface) {
   struct dlep_router_session *stream, *it;
 
   /* close TCP connection and socket */
-  avl_for_each_element_safe(&interface->session_tree, stream, _node, it) {
+  avl_for_each_element_safe(&interface->interf.session_tree, stream, _node, it) {
     dlep_router_remove_session(stream);
   }
 }
-
-/**
- * Callback triggered to send regular UDP discovery signals
- * @param ptr dlep router interface
- */
-static void
-_cb_send_discovery(void *ptr) {
-  struct dlep_router_if *interface = ptr;
-
-  if (_shutting_down) {
-    /* don't send discovery signals during shutdown */
-    return;
-  }
-
-  if (!interface->single_session
-      || avl_is_empty(&interface->session_tree)) {
-    OONF_INFO(LOG_DLEP_ROUTER, "Send UDP Peer Discovery");
-    _generate_peer_discovery(interface);
-  }
-}
-
-/**
- * Callback to receive UDP data through oonf_packet_managed API
- * @param pkt
- * @param from
- * @param ptr
- * @param length
- */
-static void
-_cb_receive_udp(struct oonf_packet_socket *pkt,
-    union netaddr_socket *from, void *ptr, size_t length) {
-  struct dlep_router_if *interface;
-  struct dlep_parser_index idx;
-  int signal;
-  struct netaddr_str nbuf;
-
-  if (_shutting_down) {
-    /* ignore UDP traffic during shutdown */
-    return;
-  }
-  interface = pkt->config.user;
-
-  if ((signal = dlep_parser_read(&idx, ptr, length, NULL)) < 0) {
-    OONF_WARN_HEX(LOG_DLEP_ROUTER, ptr, length,
-        "Could not parse incoming UDP signal from %s: %d",
-        netaddr_socket_to_string(&nbuf, from), signal);
-    return;
-  }
-
-  if (interface->single_session
-      && !avl_is_empty(&interface->session_tree)) {
-    /* ignore UDP signal */
-    return;
-  }
-
-  OONF_INFO(LOG_DLEP_ROUTER, "Received UDP Signal %u from %s",
-      signal, netaddr_socket_to_string(&nbuf, from));
-
-  if (signal != DLEP_PEER_OFFER) {
-    OONF_WARN(LOG_DLEP_ROUTER,
-        "Received illegal signal in UDP from %s: %u",
-        netaddr_socket_to_string(&nbuf, from), signal);
-    return;
-  }
-
-  _handle_peer_offer(interface, ptr, length, &idx);
-}
-
-/**
- * Get a matching local IP address for a list of remote IP addresses
- * @param remote_socket socket to connect to
- * @param ifdata interface required for local IP address
- * @param idx dlep parser index
- * @param buffer dlep signal buffer
- * @param length length of signal buffer
- * @return matching local IP address, NULL if no match
- */
-static const struct netaddr *
-_get_local_tcp_address(union netaddr_socket *remote_socket,
-    struct os_interface_data *ifdata,
-    struct dlep_parser_index *idx, uint8_t *buffer, size_t length) {
-  const struct netaddr *result = NULL;
-  struct netaddr remote_addr;
-  uint16_t pos, port;
-#ifdef OONF_LOG_DEBUG_INFO
-  struct netaddr_str nbuf;
-#endif
-
-  /* start parsing IPv6 */
-  pos = idx->idx[DLEP_IPV6_CONPOINT_TLV];
-  while (pos) {
-    dlep_parser_get_ipv6_conpoint(&remote_addr, &port, &buffer[pos]);
-
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Router offered %s:%u on interface %s",
-        netaddr_to_string(&nbuf, &remote_addr), port, ifdata->name);
-
-    if (netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, &remote_addr)) {
-      result = oonf_interface_get_prefix_from_dst(&remote_addr, ifdata);
-
-      if (result) {
-        /* we prefer IPv6 linklocal */
-        break;
-      }
-    }
-    else if (result == NULL) {
-      /* we still want an IPv6 prefix */
-      result = oonf_interface_get_prefix_from_dst(&remote_addr, NULL);
-    }
-
-    pos = dlep_parser_get_next_tlv(buffer, length, pos);
-  }
-
-  if (!result) {
-    /* parse all IPv4 addresses */
-    pos = idx->idx[DLEP_IPV4_CONPOINT_TLV];
-    while (pos) {
-      dlep_parser_get_ipv4_conpoint(&remote_addr, &port, &buffer[pos]);
-
-      OONF_DEBUG(LOG_DLEP_ROUTER, "Router offered %s:%u on interface %s",
-          netaddr_to_string(&nbuf, &remote_addr), port, ifdata->name);
-
-      result = oonf_interface_get_prefix_from_dst(&remote_addr, NULL);
-      if (result) {
-        /* at last, take an IPv4 address */
-        break;
-      }
-    }
-  }
-
-  if (result && netaddr_socket_init(remote_socket, &remote_addr, port, ifdata->index) != 0) {
-    result = NULL;
-  }
-
-  if (!result) {
-    /*
-     * no valid address, hit the manufacturers over the head for not
-     * supporting IPv6 linklocal addresses
-     */
-    OONF_WARN(LOG_DLEP_ROUTER, "No compatible address to router on interface %s",
-        ifdata->name);
-  }
-
-  return result;
-}
-
-/**
- * Handle dlep Peer Offer signal via UDP
- * @param interface dlep router interface
- * @param buffer dlep signal buffer
- * @param length signal length
- * @param idx dlep parser index
- */
-static void
-_handle_peer_offer(struct dlep_router_if *interface,
-    uint8_t *buffer, size_t length, struct dlep_parser_index *idx) {
-  const struct netaddr *local_addr;
-  struct os_interface_data *ifdata;
-  union netaddr_socket local_socket, remote_socket;
-  uint16_t pos;
-  char peer[256];
-  struct netaddr_str nbuf1;
-
-  if (idx->idx[DLEP_IPV4_CONPOINT_TLV] == 0 && idx->idx[DLEP_IPV6_CONPOINT_TLV] == 0) {
-    OONF_WARN(LOG_DLEP_ROUTER,
-        "Got UDP Peer Offer without IP TLVs");
-    return;
-  }
-
-  /* get peer type */
-  peer[0] = 0;
-  pos = idx->idx[DLEP_PEER_TYPE_TLV];
-  if (pos) {
-    dlep_parser_get_peer_type(peer, &buffer[pos]);
-
-    OONF_INFO(LOG_DLEP_ROUTER, "Radio peer type: %s", peer);
-  }
-
-  /* get interface data for IPv6 LL */
-  ifdata = &interface->udp._if_listener.interface->data;
-
-  /* get prefix for local tcp socket */
-  local_addr = _get_local_tcp_address(&remote_socket, ifdata, idx, buffer, length);
-  if (!local_addr) {
-    return;
-  }
-
-  /* open TCP session to radio */
-  if (netaddr_socket_init(&local_socket, local_addr, 0, ifdata->index)) {
-    OONF_WARN(LOG_DLEP_ROUTER,
-        "Malformed socket data for DLEP session for %s (%u): %s",
-        ifdata->name, ifdata->index,
-        netaddr_to_string(&nbuf1, local_addr));
-    return;
-  }
-
-  dlep_router_add_session(interface, &local_socket, &remote_socket);
-}
-
-static void
-_generate_peer_discovery(struct dlep_router_if *interface) {
-  dlep_writer_start_signal(DLEP_PEER_DISCOVERY);
-
-  dlep_writer_add_version_tlv(DLEP_VERSION_MAJOR, DLEP_VERSION_MINOR);
-  if (dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
-    return;
-  }
-
-  dlep_writer_send_udp_multicast(&interface->udp, LOG_DLEP_ROUTER);
-}
index c65d41e..2c67a68 100644 (file)
 #define DLEP_ROUTER_INTERFACE_H_
 
 #include "common/common_types.h"
-#include "common/avl.h"
-#include "subsystems/oonf_packet_socket.h"
-#include "subsystems/oonf_timer.h"
 
-struct dlep_router_if {
-  /* name of interface for layer2 database */
-  char l2_destination[IF_NAMESIZE];
-
-  /* UDP socket for discovery */
-  struct oonf_packet_managed udp;
-  struct oonf_packet_managed_config udp_config;
-
-  /* event timer (either discovery or heartbeat) */
-  struct oonf_timer_instance discovery_timer;
-
-  /* local timer settings */
-  uint64_t local_discovery_interval;
-  uint64_t local_heartbeat_interval;
+#include "dlep/dlep_session.h"
+#include "dlep/dlep_interface.h"
 
-  /* true if router should not accept further sessions */
-  bool single_session;
-
-  /* hook into session tree, interface name is the key */
-  struct avl_node _node;
-
-  /* list of all streams on this interface */
-  struct avl_tree session_tree;
+struct dlep_router_if {
+  struct dlep_if interf;
 };
 
 void dlep_router_interface_init(void);
 void dlep_router_interface_cleanup(void);
 
-struct dlep_router_if *dlep_router_get_interface(const char *ifname);
+struct dlep_router_if *dlep_router_get_by_layer2_if(const char *ifname);
+struct dlep_router_if *dlep_router_get_by_datapath_if(const char *ifname);
 struct dlep_router_if *dlep_router_add_interface(const char *ifname);
 void dlep_router_remove_interface(struct dlep_router_if *);
 
index 75cf001..a933c44 100644 (file)
 
 #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"
 
 #include "dlep/dlep_iana.h"
-#include "dlep/dlep_parser.h"
-#include "dlep/dlep_static_data.h"
+#include "dlep/dlep_session.h"
 #include "dlep/dlep_writer.h"
 #include "dlep/router/dlep_router.h"
 #include "dlep/router/dlep_router_interface.h"
 
 static void _cb_tcp_lost(struct oonf_stream_session *);
 static enum oonf_stream_session_state _cb_tcp_receive_data(struct oonf_stream_session *);
-
-static void _cb_send_heartbeat(void *);
-static void _cb_heartbeat_timeout(void *);
-
-static void _handle_peer_initialization_ack(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static int _handle_peer_termination_ack(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static int _handle_peer_termination(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static void _handle_destination_up(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static void _handle_destination_update(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-static void _handle_destination_down(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx);
-
-static void _handle_metrics(struct oonf_layer2_data *neighbor_data,
-    const uint8_t *buffer, const struct dlep_parser_index *idx);
-
-static int _generate_peer_initialization(struct dlep_router_session *session);
-static void _generate_heartbeat(struct dlep_router_session *session);
-static void _generate_peer_termination(struct dlep_router_session *session);
-static int _generate_peer_termination_ack(struct dlep_router_session *session);
-static void _generate_destination_up_ack(struct dlep_router_session *session,
-    struct netaddr *neighbor, enum dlep_status status);
-static void _generate_destination_down_ack(struct dlep_router_session *session,
-    struct netaddr *neighbor, enum dlep_status status);
+static void _cb_send_buffer(struct dlep_session *session, int af_family);
+static void _cb_end_session(struct dlep_session *session);
 
 /* session objects */
-static struct oonf_class _router_stream_class = {
+static struct oonf_class _router_session_class = {
   .name = "DLEP router stream",
   .size = sizeof(struct dlep_router_session),
 };
 
-static struct oonf_timer_class _heartbeat_timer_class = {
-  .name = "DLEP router heartbeat",
-  .callback = _cb_send_heartbeat,
-  .periodic = true,
-};
-
-static struct oonf_timer_class _heartbeat_timeout_class = {
-  .name = "DLEP router timeout",
-  .callback = _cb_heartbeat_timeout,
-};
-
 static uint32_t _l2_origin;
 
 /**
@@ -116,9 +78,7 @@ static uint32_t _l2_origin;
  */
 void
 dlep_router_session_init(void) {
-  oonf_class_add(&_router_stream_class);
-  oonf_timer_add(&_heartbeat_timer_class);
-  oonf_timer_add(&_heartbeat_timeout_class);
+  oonf_class_add(&_router_session_class);
 
   _l2_origin = oonf_layer2_register_origin();
 }
@@ -128,9 +88,7 @@ dlep_router_session_init(void) {
  */
 void
 dlep_router_session_cleanup(void) {
-  oonf_timer_remove(&_heartbeat_timeout_class);
-  oonf_timer_remove(&_heartbeat_timer_class);
-  oonf_class_remove(&_router_stream_class);
+  oonf_class_remove(&_router_session_class);
 }
 
 /**
@@ -144,7 +102,7 @@ dlep_router_get_session(struct dlep_router_if *interf,
     union netaddr_socket *remote) {
   struct dlep_router_session *session;
 
-  return avl_find_element(&interf->session_tree, remote, session, _node);
+  return avl_find_element(&interf->interf.session_tree, remote, session, _node);
 }
 
 /**
@@ -157,221 +115,101 @@ dlep_router_get_session(struct dlep_router_if *interf,
 struct dlep_router_session *
 dlep_router_add_session(struct dlep_router_if *interf,
     union netaddr_socket *local, union netaddr_socket *remote) {
-  struct dlep_router_session *session;
+  struct dlep_router_session *router_session;
+  struct dlep_extension *ext;
   struct netaddr_str nbuf1, nbuf2;
 
-  session = dlep_router_get_session(interf, remote);
-  if (session) {
-    return session;
+  router_session = dlep_router_get_session(interf, remote);
+  if (router_session) {
+    OONF_DEBUG(LOG_DLEP_ROUTER, "use existing instance on"
+        " %s for %s", interf->interf.l2_ifname, netaddr_socket_to_string(&nbuf1, remote));
+    return router_session;
   }
 
   /* initialize tcp session instance */
-  session = oonf_class_malloc(&_router_stream_class);
-  if (!session) {
+  router_session = oonf_class_malloc(&_router_session_class);
+  if (!router_session) {
     return NULL;
   }
 
   /* initialize tree node */
-  memcpy(&session->remote_socket, remote, sizeof(*remote));
-  session->_node.key = &session->remote_socket;
+  memcpy(&router_session->remote_socket, remote, sizeof(*remote));
+  router_session->_node.key = &router_session->remote_socket;
 
   /* configure and open TCP session */
-  session->tcp.config.session_timeout = 120000; /* 120 seconds */
-  session->tcp.config.maximum_input_buffer = 4096;
-  session->tcp.config.allowed_sessions = 3;
-  session->tcp.config.cleanup = _cb_tcp_lost;
-  session->tcp.config.receive_data = _cb_tcp_receive_data;
+  router_session->tcp.config.session_timeout = 120000; /* 120 seconds */
+  router_session->tcp.config.maximum_input_buffer = 4096;
+  router_session->tcp.config.allowed_sessions = 3;
+  router_session->tcp.config.cleanup = _cb_tcp_lost;
+  router_session->tcp.config.receive_data = _cb_tcp_receive_data;
 
   OONF_DEBUG(LOG_DLEP_ROUTER, "Connect DLEP session from %s to %s",
       netaddr_socket_to_string(&nbuf1, local),
       netaddr_socket_to_string(&nbuf2, remote));
 
-  if (oonf_stream_add(&session->tcp, local)) {
+  if (oonf_stream_add(&router_session->tcp, local)) {
     OONF_WARN(LOG_DLEP_ROUTER,
         "Could not open TCP client for local address %s",
         netaddr_socket_to_string(&nbuf1, local));
-    oonf_class_free(&_router_stream_class, session);
+    dlep_router_remove_session(router_session);
     return NULL;
   }
 
-  session->stream = oonf_stream_connect_to(&session->tcp, remote);
-  if (!session->stream) {
+  /* copy socket information */
+  memcpy(&router_session->session.remote_socket, remote,
+      sizeof(router_session->session.remote_socket));
+
+  router_session->stream = oonf_stream_connect_to(&router_session->tcp, remote);
+  if (!router_session->stream) {
     OONF_WARN(LOG_DLEP_ROUTER,
         "Could not open TCP client on from %s to %s",
         netaddr_socket_to_string(&nbuf1, local),
         netaddr_socket_to_string(&nbuf2, remote));
-    oonf_stream_remove(&session->tcp, true);
-    oonf_class_free(&_router_stream_class, session);
+    dlep_router_remove_session(router_session);
     return NULL;
   }
 
-  /* initialize back pointer */
-  session->interface = interf;
-
-  /* initialize timers */
-  session->heartbeat_timer.cb_context = session;
-  session->heartbeat_timer.class = &_heartbeat_timer_class;
-
-  session->heartbeat_timeout.cb_context = session;
-  session->heartbeat_timeout.class = &_heartbeat_timeout_class;
-
-  if (_generate_peer_initialization(session)) {
-    OONF_WARN(LOG_DLEP_ROUTER, "Could not send peer initialization to %s",
-        netaddr_socket_to_string(&nbuf1, remote));
-    oonf_stream_remove(&session->tcp, true);
-    oonf_class_free(&_router_stream_class, session);
+  if (dlep_session_add(&router_session->session,
+      interf->interf.l2_ifname, interf->interf.session.l2_origin,
+      &router_session->stream->out, false, LOG_DLEP_ROUTER)) {
+    dlep_router_remove_session(router_session);
     return NULL;
   }
+  router_session->session.next_signal = DLEP_PEER_INITIALIZATION_ACK;
+  router_session->session.cb_send_buffer = _cb_send_buffer;
+  router_session->session.cb_end_session = _cb_end_session;
+  memcpy(&router_session->session.cfg, &interf->interf.session.cfg,
+      sizeof(router_session->session.cfg));
+  memcpy(&router_session->session.remote_socket, remote,
+      sizeof(router_session->session.remote_socket));
 
-  /* start heartbeat timeout */
-  oonf_timer_set(&session->heartbeat_timeout, 2000);
-
-  /* start heartbeat */
-  oonf_timer_set(&session->heartbeat_timer,
-      interf->local_heartbeat_interval);
+  /* initialize back pointer */
+  router_session->interface = interf;
 
   /* add session to interface */
-  avl_insert(&interf->session_tree, &session->_node);
+  avl_insert(&interf->interf.session_tree, &router_session->_node);
 
-  return session;
-}
-
-/**
- * Remove existing dlep router session
- * @param session dlep router session
- */
-void
-dlep_router_remove_session(struct dlep_router_session *session) {
-  if (session->stream) {
-    oonf_stream_close(session->stream);
-  }
-  oonf_stream_remove(&session->tcp, false);
-
-  oonf_timer_stop(&session->heartbeat_timeout);
-  oonf_timer_stop(&session->heartbeat_timer);
-  avl_remove(&session->interface->session_tree, &session->_node);
-  oonf_class_free(&_router_stream_class, session);
-}
-
-/**
- * Send peer termination to radio
- * @param session
- */
-void
-dlep_router_terminate_session(struct dlep_router_session *session) {
-  if (session->state != DLEP_ROUTER_SESSION_ACTIVE) {
-    return;
-  }
-
-  _generate_peer_termination(session);
-}
-
-/**
- *
- * @param tcp_session
- * @param session
- * @return -1 if an error happened, 1 if signal was parsed,
- *    0 if buffer needs more bytes for a signal
- */
-static int
-_parse_signal(struct oonf_stream_session *tcp_session,
-    struct dlep_router_session *session) {
-  struct dlep_parser_index idx;
-  uint16_t siglen;
-  int signal, result;
-  struct netaddr_str nbuf;
-
-  if ((signal = dlep_parser_read(&idx, abuf_getptr(&tcp_session->in),
-      abuf_getlen(&tcp_session->in), &siglen)) < 0) {
-    if (signal != DLEP_PARSER_INCOMPLETE_HEADER
-        && signal != DLEP_PARSER_INCOMPLETE_SIGNAL) {
-      OONF_WARN_HEX(LOG_DLEP_ROUTER,
-          abuf_getptr(&tcp_session->in), abuf_getlen(&tcp_session->in),
-          "Could not parse incoming TCP signal from %s: %d",
-          netaddr_socket_to_string(&nbuf, &tcp_session->remote_socket),
-          signal);
-      return -1;
+  /* inform all extensions */
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (ext->cb_session_init_router) {
+      ext->cb_session_init_router(&router_session->session);
     }
-    return 0;
-  }
-
-  if (session->state == DLEP_ROUTER_SESSION_INIT
-      && signal != DLEP_PEER_INITIALIZATION_ACK) {
-    OONF_WARN(LOG_DLEP_ROUTER,
-        "Received TCP signal %d before Peer Initialization", signal);
-    return -1;
-  }
-
-  if (session->state == DLEP_ROUTER_SESSION_TERMINATE
-      && signal != DLEP_PEER_TERMINATION_ACK) {
-    OONF_DEBUG(LOG_DLEP_ROUTER,
-        "Ignore signal %d when waiting for Termination Ack", signal);
-
-    /* remove signal from input buffer */
-    abuf_pull(&tcp_session->in, siglen);
-
-    return 1;
-  }
-
-  OONF_INFO(LOG_DLEP_ROUTER, "Received TCP signal %d", signal);
-
-  result = 0;
-  switch (signal) {
-    case DLEP_PEER_INITIALIZATION_ACK:
-      _handle_peer_initialization_ack(
-          session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_HEARTBEAT:
-      OONF_DEBUG(LOG_DLEP_ROUTER, "Received TCP heartbeat, reset interval to %"PRIu64,
-          session->remote_heartbeat_interval * 2);
-      oonf_timer_set(&session->heartbeat_timeout, session->remote_heartbeat_interval * 2);
-      break;
-    case DLEP_PEER_TERMINATION:
-      result = _handle_peer_termination(
-          session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_PEER_TERMINATION_ACK:
-      result = _handle_peer_termination_ack(
-          session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_DESTINATION_UP:
-      _handle_destination_up(session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_DESTINATION_UPDATE:
-      _handle_destination_update(session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-    case DLEP_DESTINATION_DOWN:
-      _handle_destination_down(session, abuf_getptr(&tcp_session->in), &idx);
-      break;
-
-    default:
-      OONF_WARN(LOG_DLEP_ROUTER,
-          "Received illegal signal in TCP from %s: %u",
-          netaddr_to_string(&nbuf, &tcp_session->remote_address), signal);
-      return STREAM_SESSION_CLEANUP;
   }
 
-  /* remove signal from input buffer */
-  abuf_pull(&tcp_session->in, siglen);
 
-  return result != 0 ? -1 : 1;
+  return router_session;
 }
 
 /**
- * Receive tcp data via oonf_stream_socket
- * @param tcp_session
- * @return
+ * Remove existing dlep router session
+ * @param session dlep router session
  */
-static enum oonf_stream_session_state
-_cb_tcp_receive_data(struct oonf_stream_session *tcp_session) {
-  struct dlep_router_session *session;
-  int result;
-
-  session = container_of(tcp_session->comport, struct dlep_router_session, tcp);
-
-  while ((result = _parse_signal(tcp_session, session)) == 1);
-
-  return result == -1 ? STREAM_SESSION_CLEANUP : STREAM_SESSION_ACTIVE;
+void
+dlep_router_remove_session(struct dlep_router_session *router_session) {
+  if (router_session->stream) {
+    oonf_stream_close(router_session->stream);
+  }
+  oonf_stream_remove(&router_session->tcp, true);
 }
 
 /**
@@ -380,464 +218,70 @@ _cb_tcp_receive_data(struct oonf_stream_session *tcp_session) {
  */
 static void
 _cb_tcp_lost(struct oonf_stream_session *tcp_session) {
-  struct dlep_router_session *session;
-  struct oonf_layer2_destination *l2dst, *l2dst_it;
-  struct oonf_layer2_neigh *l2neigh, *l2neigh_it;
-  struct oonf_layer2_net *l2net;
-
-  session = container_of(tcp_session->comport, struct dlep_router_session, tcp);
-
-  OONF_INFO(LOG_DLEP_ROUTER, "tcp session lost");
-
-  /* just to be sure */
-  session->state = DLEP_ROUTER_SESSION_TERMINATE;
-  session->stream = NULL;
-
-  /* cleanup layer2 data */
-  l2net = oonf_layer2_net_get(session->interface->l2_destination);
-  if (l2net) {
-    avl_for_each_element_safe(&l2net->neighbors, l2neigh, _node, l2neigh_it) {
-      avl_for_each_element_safe(&l2neigh->destinations, l2dst, _node, l2dst_it) {
-        if (l2dst->origin == _l2_origin) {
-          oonf_layer2_destination_remove(l2dst);
-        }
-      }
-      oonf_layer2_neigh_cleanup(l2neigh, _l2_origin);
-      oonf_layer2_neigh_commit(l2neigh);
-    }
-    oonf_layer2_net_cleanup(l2net, _l2_origin);
-    oonf_layer2_net_commit(l2net);
-  }
-
-  /* no heartbeats anymore */
-  oonf_timer_stop(&session->heartbeat_timer);
-
-  /* trigger lazy cleanup */
-  oonf_timer_set(&session->heartbeat_timeout, 1);
-}
-
-/**
- * Callback triggered to send regular heartbeats via TCP
- * @param ptr dlep router session
- */
-static void
-_cb_send_heartbeat(void *ptr) {
-  struct dlep_router_session *session = ptr;
-
-  OONF_DEBUG(LOG_DLEP_ROUTER, "Send Heartbeat (%"PRIu64")",
-      session->interface->local_heartbeat_interval);
-
-  _generate_heartbeat(session);
-}
-
-/**
- * Callback triggered when remote heartbeat times out
- * @param ptr dlep router session
- */
-static void
-_cb_heartbeat_timeout(void *ptr) {
-  struct dlep_router_session *session = ptr;
-
-  OONF_INFO(LOG_DLEP_ROUTER, "Heartbeat timeout");
-
-  /* close session */
-  dlep_router_remove_session(session);
-}
-
-/**
- * Handle incoming peer initialization ack signal
- * @param session dlep router session
- * @param ptr begin of signal
- * @param idx dlep parser index
- */
-static void
-_handle_peer_initialization_ack(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  struct oonf_layer2_net *l2net;
-  uint8_t *buffer;
-  char peer[256];
-  int pos;
-  uint16_t version[2];
-
-  buffer = ptr;
-
-  /* get version */
-  pos = idx->idx[DLEP_VERSION_TLV];
-  dlep_parser_get_version(&version[0], &version[1], &buffer[pos]);
-  if (version[0] == DLEP_VERSION_MAJOR && version[1] < DLEP_VERSION_MINOR) {
-    OONF_WARN(LOG_DLEP_ROUTER, "Received peer discovery with version: %u/%u",
-        version[0], version[1]);
-    return;
-  }
-
-  /* activate session */
-  session->state = DLEP_ROUTER_SESSION_ACTIVE;
-
-  /* get peer type */
-  peer[0] = 0;
-  pos = idx->idx[DLEP_PEER_TYPE_TLV];
-  if (pos) {
-    dlep_parser_get_peer_type(peer, &buffer[pos]);
-
-    OONF_INFO(LOG_DLEP_ROUTER, "Radio peer type: %s", peer);
-  }
-
-  /* get heartbeat interval */
-  pos = idx->idx[DLEP_HEARTBEAT_INTERVAL_TLV];
-  dlep_parser_get_heartbeat_interval(
-      &session->remote_heartbeat_interval, &buffer[pos]);
-
-  OONF_DEBUG(LOG_DLEP_ROUTER, "Heartbeat interval is %"PRIu64,
-      session->remote_heartbeat_interval);
-
-  /* reset heartbeat timeout */
-  oonf_timer_set(&session->heartbeat_timeout, session->remote_heartbeat_interval*2);
-
-  OONF_DEBUG(LOG_DLEP_ROUTER, "Received default metrics for interface %s",
-      session->interface->l2_destination);
-
-  l2net = oonf_layer2_net_add(session->interface->l2_destination);
-  if (!l2net) {
-    /* out of memory, terminate dlep session */
-    dlep_router_terminate_session(session);
-    return;
-  }
-
-  _handle_metrics(&l2net->neighdata[0], buffer, idx);
-}
-
-
-/**
- * Handle peer termination from radio
- * @param session dlep router session
- * @param ptr pointer to begin of signal
- * @param idx dlep parser index
- * @return -1 if an error happened, 0 otherwise
- */
-static int
-_handle_peer_termination(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  uint8_t *buffer = ptr;
-  enum dlep_status status;
-  int pos;
-
-  pos = idx->idx[DLEP_STATUS_TLV];
-  if (pos) {
-    dlep_parser_get_status(&status, &buffer[pos]);
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Peer termination status: %u",
-        status);
-  }
-
-  return _generate_peer_termination_ack(session);
-}
-
-/**
- * Handle peer termination ack from radio
- * @param session dlep router session
- * @param ptr pointer to begin of signal
- * @param idx dlep parser index
- * @return -1 if an error happened, 0 otherwise
- */
-static int
-_handle_peer_termination_ack(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  uint8_t *buffer = ptr;
-  enum dlep_status status;
-  int pos;
-  struct netaddr_str nbuf;
-
-  pos = idx->idx[DLEP_STATUS_TLV];
-  if (pos) {
-    dlep_parser_get_status(&status, &buffer[pos]);
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Peer termination ack status: %u",
-        status);
-  }
-
-  if (session->state != DLEP_ROUTER_SESSION_TERMINATE) {
-    OONF_WARN(LOG_DLEP_ROUTER, "Got Peer Termination ACK without"
-        " sending a Peer Terminate from %s",
-        netaddr_socket_to_string(&nbuf, &session->stream->remote_socket));
-  }
-
-  /* terminate session */
-  return -1;
-}
-
-static void
-_handle_destination_up(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  struct netaddr mac;
-  uint8_t *buffer;
-  int pos;
-  struct oonf_layer2_net *l2net;
-  struct oonf_layer2_neigh *l2neigh;
-#ifdef OONF_LOG_INFO
-  struct netaddr_str nbuf;
-#endif
-
-  buffer = ptr;
-
-  /* get mac address of new destination */
-  pos = idx->idx[DLEP_MAC_ADDRESS_TLV];
-  dlep_parser_get_mac_addr(&mac, &buffer[pos]);
-  OONF_INFO(LOG_DLEP_ROUTER, "New destination came up: %s",
-      netaddr_to_string(&nbuf, &mac));
-
-  l2net = oonf_layer2_net_add(session->interface->l2_destination);
-  if (!l2net) {
-    _generate_destination_up_ack(session, &mac, DLEP_STATUS_ERROR);
-    return;
-  }
-
-  if (l2net->if_type == OONF_LAYER2_TYPE_UNDEFINED) {
-    l2net->if_type = OONF_LAYER2_TYPE_DLEP;
-  }
-
-  l2neigh = oonf_layer2_neigh_add(l2net, &mac);
-  if (!l2neigh) {
-    _generate_destination_up_ack(session, &mac, DLEP_STATUS_ERROR);
-    return;
-  }
-
-  _handle_metrics(&l2neigh->data[0], buffer, idx);
-  oonf_layer2_neigh_commit(l2neigh);
-
-  _generate_destination_up_ack(session, &mac, DLEP_STATUS_OKAY);
-}
-
-static void
-_handle_destination_update(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  struct netaddr mac;
-  uint8_t *buffer;
-  int pos;
-  struct oonf_layer2_net *l2net;
-  struct oonf_layer2_neigh *l2neigh;
-#ifdef OONF_LOG_INFO
-  struct netaddr_str nbuf;
-#endif
-
-  buffer = ptr;
-
-  /* get mac address of new destination */
-  pos = idx->idx[DLEP_MAC_ADDRESS_TLV];
-  dlep_parser_get_mac_addr(&mac, &buffer[pos]);
-  OONF_INFO(LOG_DLEP_ROUTER, "Update for destination: %s",
-      netaddr_to_string(&nbuf, &mac));
-
-  l2net = oonf_layer2_net_get(session->interface->l2_destination);
-  if (!l2net) {
-    OONF_INFO(LOG_DLEP_ROUTER, "L2 network for interface %s is not there",
-        session->interface->l2_destination);
-    return;
-  }
-
-  l2neigh = oonf_layer2_neigh_get(l2net, &mac);
-  if (!l2neigh) {
-    OONF_INFO(LOG_DLEP_ROUTER, "L2 neighbor %s for interface %s is not there",
-        netaddr_to_string(&nbuf, &mac), session->interface->l2_destination);
-    return;
-  }
-
-  _handle_metrics(&l2neigh->data[0], buffer, idx);
-  oonf_layer2_neigh_commit(l2neigh);
-}
-
-static void
-_handle_destination_down(struct dlep_router_session *session,
-    void *ptr, struct dlep_parser_index *idx) {
-  struct netaddr mac;
-  uint8_t *buffer;
-  int pos;
-  struct oonf_layer2_net *l2net;
-  struct oonf_layer2_neigh *l2neigh;
-#ifdef OONF_LOG_INFO
+  struct dlep_extension *ext;
+  struct dlep_router_session *router_session;
+#ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str nbuf;
 #endif
-  buffer = ptr;
 
-  /* get mac address of new destination */
-  pos = idx->idx[DLEP_MAC_ADDRESS_TLV];
-  dlep_parser_get_mac_addr(&mac, &buffer[pos]);
-  OONF_INFO(LOG_DLEP_ROUTER, "New destination came up: %s",
-      netaddr_to_string(&nbuf, &mac));
+  router_session = container_of(tcp_session->comport, struct dlep_router_session, tcp);
 
-  l2net = oonf_layer2_net_get(session->interface->l2_destination);
-  if (!l2net) {
-    return;
-  }
-
-  l2neigh = oonf_layer2_neigh_get(l2net, &mac);
-  if (!l2neigh) {
-    return;
-  }
-
-  oonf_layer2_neigh_remove(l2neigh, _l2_origin);
-
-  _generate_destination_down_ack(session, &mac, DLEP_STATUS_OKAY);
-}
+  OONF_DEBUG(LOG_DLEP_ROUTER, "Lost tcp session to %s",
+      netaddr_socket_to_string(&nbuf, &tcp_session->remote_socket));
 
-static void
-_handle_uint64_metric(struct oonf_layer2_data *neighbor_data,
-    enum oonf_layer2_neighbor_index l2datatype,
-    const char *text_type __attribute__((unused)),
-    const uint8_t *buffer,
-    const struct dlep_parser_index *idx, enum dlep_tlvs dleptlv) {
-  uint64_t data;
-  int pos;
-
-  pos = idx->idx[dleptlv];
-  if (pos) {
-    dlep_parser_get_uint64(&data, &buffer[pos]);
-
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Received %s: %" PRIu64, text_type, data);
-
-    oonf_layer2_set_value(&neighbor_data[l2datatype], _l2_origin, data);
-  }
-}
-
-static void
-_handle_metrics(struct oonf_layer2_data *neighbor_data,
-    const uint8_t *buffer, const struct dlep_parser_index *idx) {
-  int32_t sig;
-  int pos;
-
-  for (pos = 0; pos < OONF_LAYER2_NEIGH_COUNT; pos++) {
-    if (oonf_layer2_get_origin(&neighbor_data[pos]) == _l2_origin) {
-      oonf_layer2_reset_value(&neighbor_data[pos]);
+  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
+    if (ext->cb_session_cleanup_router) {
+      ext->cb_session_cleanup_router(&router_session->session);
     }
   }
 
-  /* get metric values */
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_RX_MAX_BITRATE,
-      "mdrr", buffer, idx, DLEP_MDRR_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_TX_MAX_BITRATE,
-      "mdrt", buffer, idx, DLEP_MDRT_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_RX_BITRATE,
-      "cdrr", buffer, idx, DLEP_CDRR_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_TX_BITRATE,
-      "cdrt", buffer, idx, DLEP_CDRT_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_RX_BYTES,
-      "byte-count (r)", buffer, idx, DLEP_BYTES_R_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_TX_BYTES,
-      "byte-count (r)", buffer, idx, DLEP_BYTES_T_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_RX_FRAMES,
-      "frame-count (r)", buffer, idx, DLEP_FRAMES_R_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_TX_FRAMES,
-      "frame-count (r)", buffer, idx, DLEP_FRAMES_T_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_TX_RETRIES,
-      "frame-retries (t)", buffer, idx, DLEP_FRAMES_RETRIES_TLV);
-  _handle_uint64_metric(neighbor_data, OONF_LAYER2_NEIGH_TX_FAILED,
-      "frame-fails (t)", buffer, idx, DLEP_FRAMES_FAILED_TLV);
-
-  pos = idx->idx[DLEP_TX_SIGNAL_TLV];
-  if (pos) {
-    dlep_parser_get_tx_signal(&sig, &buffer[pos]);
-
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Received tx-signal strength: %d", sig);
-
-    oonf_layer2_set_value(&neighbor_data[OONF_LAYER2_NEIGH_TX_SIGNAL], _l2_origin, sig);
-  }
-  pos = idx->idx[DLEP_RX_SIGNAL_TLV];
-  if (pos) {
-    dlep_parser_get_rx_signal(&sig, &buffer[pos]);
-
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Received rx-signal strength: %d", sig);
-
-    oonf_layer2_set_value(&neighbor_data[OONF_LAYER2_NEIGH_RX_SIGNAL], _l2_origin, sig);
-  }
+  /* kill embedded session object */
+  dlep_session_remove(&router_session->session);
 
-  pos = idx->idx[DLEP_LATENCY_TLV];
-  if (pos) {
-    uint32_t latency;
-    dlep_parser_get_latency(&latency, &buffer[pos]);
 
-    OONF_DEBUG(LOG_DLEP_ROUTER, "Received latency: %d", latency);
-
-    oonf_layer2_set_value(&neighbor_data[OONF_LAYER2_NEIGH_LATENCY], _l2_origin, latency);
-  }
+  /* remove from session tree of interface */
+  avl_remove(&router_session->interface->interf.session_tree,
+      &router_session->_node);
 }
 
 /**
- * Send a peer initialization signal
- * @param session dlep router session
- * @return -1 if an error happened, 0 otherwise
+ * Receive tcp data via oonf_stream_socket
+ * @param tcp_session
+ * @return
  */
-static int
-_generate_peer_initialization(struct dlep_router_session *session) {
-  /* create Peer Initialization */
-  OONF_INFO(LOG_DLEP_ROUTER, "Send Peer Initialization");
-
-  dlep_writer_start_signal(DLEP_PEER_INITIALIZATION);
-
-  /* add tlvs */
-  dlep_writer_add_version_tlv(DLEP_VERSION_MAJOR, DLEP_VERSION_MINOR);
-  dlep_writer_add_heartbeat_tlv(session->interface->local_heartbeat_interval);
+static enum oonf_stream_session_state
+_cb_tcp_receive_data(struct oonf_stream_session *tcp_session) {
+  struct dlep_router_session *router_session;
 
-  if (dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
-    return -1;
-  }
+  router_session = container_of(tcp_session->comport, struct dlep_router_session, tcp);
 
-  dlep_writer_send_tcp_unicast(session->stream, LOG_DLEP_ROUTER);
-  return 0;
+  return dlep_session_process_tcp(tcp_session, &router_session->session);
 }
 
 static void
-_generate_heartbeat(struct dlep_router_session *session) {
-  dlep_writer_start_signal(DLEP_HEARTBEAT);
+_cb_send_buffer(struct dlep_session *session,
+    int af_family __attribute((unused))) {
+  struct dlep_router_session *router_session;
 
-  if (dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
+  if (!abuf_getlen(session->writer.out)) {
     return;
   }
 
-  dlep_writer_send_tcp_unicast(session->stream, LOG_DLEP_ROUTER);
-}
-
-static void
-_generate_peer_termination(struct dlep_router_session *session) {
-  dlep_writer_start_signal(DLEP_PEER_TERMINATION);
-  dlep_writer_add_status(DLEP_STATUS_OKAY);
-  if (!dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
-    dlep_writer_send_tcp_unicast(session->stream, LOG_DLEP_ROUTER);
-
-    session->state = DLEP_ROUTER_SESSION_TERMINATE;
-  }
-}
-
-static int
-_generate_peer_termination_ack(struct dlep_router_session *session) {
-  /* send Peer Termination Ack */
-  dlep_writer_start_signal(DLEP_PEER_TERMINATION_ACK);
-  dlep_writer_add_status(DLEP_STATUS_OKAY);
+  OONF_DEBUG(session->log_source, "Send buffer %" PRIu64 " bytes",
+      abuf_getlen(session->writer.out));
 
-  if (dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
-    return -1;
-  }
+  /* get pointer to radio interface */
+  router_session = container_of(session, struct dlep_router_session, session);
 
-  dlep_writer_send_tcp_unicast(session->stream, LOG_DLEP_ROUTER);
-  return 0;
+  oonf_stream_flush(router_session->stream);
 }
 
 static void
-_generate_destination_up_ack(struct dlep_router_session *session,
-    struct netaddr *neighbor, enum dlep_status status) {
-  dlep_writer_start_signal(DLEP_DESTINATION_UP_ACK);
-  dlep_writer_add_mac_tlv(neighbor);
-  dlep_writer_add_status(status);
-
-  if (!dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
-    dlep_writer_send_tcp_unicast(session->stream, LOG_DLEP_ROUTER);
-  }
-}
+_cb_end_session(struct dlep_session *session) {
+  struct dlep_router_session *router_session;
 
-static void
-_generate_destination_down_ack(struct dlep_router_session *session,
-    struct netaddr *neighbor, enum dlep_status status) {
-  dlep_writer_start_signal(DLEP_DESTINATION_DOWN_ACK);
-  dlep_writer_add_mac_tlv(neighbor);
-  dlep_writer_add_status(status);
-
-  if (!dlep_writer_finish_signal(LOG_DLEP_ROUTER)) {
-    dlep_writer_send_tcp_unicast(session->stream, LOG_DLEP_ROUTER);
-  }
+  /* get pointer to radio interface */
+  router_session = container_of(session, struct dlep_router_session, session);
+
+  dlep_router_remove_session(router_session);
 }
index 592c757..4805421 100644 (file)
@@ -57,30 +57,21 @@ enum dlep_router_session_state {
 };
 
 struct dlep_router_session {
+  /* basic content for tcp stream */
+  struct oonf_stream_session *stream;
+
   /* remote socket of radio */
   union netaddr_socket remote_socket;
 
   /* TCP client socket for session */
   struct oonf_stream_socket tcp;
 
-  /* tcp stream session */
-  struct oonf_stream_session *stream;
+  /* generic DLEP session */
+  struct dlep_session session;
 
   /* back pointer to interface session */
   struct dlep_router_if *interface;
 
-  /* state of the DLEP session */
-  enum dlep_router_session_state state;
-
-  /* timer to generate heartbeats */
-  struct oonf_timer_instance heartbeat_timer;
-
-  /* keep track of various timeouts */
-  struct oonf_timer_instance heartbeat_timeout;
-
-  /* heartbeat settings from the other side of the session */
-  uint64_t remote_heartbeat_interval;
-
   /* remember all streams bound to an interface */
   struct avl_node _node;
 };
@@ -96,6 +87,5 @@ struct dlep_router_session *dlep_router_add_session(
 void dlep_router_remove_session(struct dlep_router_session *);
 
 int dlep_router_send_peer_initialization(struct dlep_router_session *);
-void dlep_router_terminate_session(struct dlep_router_session *session);
 
 #endif /* DLEP_ROUTER_SESSION_H_ */
index cd73a78..5356423 100644 (file)
@@ -1,5 +1,6 @@
 # build framework
 add_subdirectory(dlep-radio)
+add_subdirectory(dlep-router)
 add_subdirectory(olsrd2)
 add_subdirectory(olsrd2-sliver)
 add_subdirectory(oonf)
diff --git a/src/dlep-router/CMakeLists.txt b/src/dlep-router/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7d17b96
--- /dev/null
@@ -0,0 +1,53 @@
+###########################################
+#### Default Application configuration ####
+###########################################
+
+# set name of program the executable and library prefix
+set (OONF_APP "DLEP Router")
+set (OONF_EXE dlep_router)
+
+# setup custom text before and after default help message
+set (OONF_HELP_PREFIX "DLEP Router daemon\\n")
+set (OONF_HELP_SUFFIX "Visit http://www.olsr.org\\n")
+
+# setup custom text after version string
+set (OONF_VERSION_TRAILER "Visit http://www.olsr.org\\n")
+
+# set to true to stop application running without root privileges (true/false)
+set (OONF_NEED_ROOT false)
+
+# name of default configuration handler
+set (OONF_APP_DEFAULT_CFG_HANDLER Compact)
+
+#################################
+####  set static subsystems  ####
+#################################
+
+IF (NOT OONF_STATIC_PLUGINS)
+    set (OONF_STATIC_PLUGINS class
+                             clock
+                             interface
+                             layer2
+                             packet_socket
+                             socket
+                             stream_socket
+                             telnet
+                             timer
+                             viewer
+                             os_clock
+                             os_socket
+                             os_interface
+                             os_system
+                             cfg_compact
+                             layer2info
+                             systeminfo
+                             dlep_router
+                             )
+ENDIF (NOT OONF_STATIC_PLUGINS)
+
+##################################
+#### link framework libraries ####
+##################################
+
+include(../../cmake/link_app.cmake)
+oonf_create_app("${OONF_EXE}" "${OONF_STATIC_PLUGINS}")
index f710a10..c6f0475 100644 (file)
@@ -54,6 +54,7 @@ IF (NOT OONF_STATIC_PLUGINS)
                              olsrv2info
                              netjsoninfo
                              lan_import
+                             http
                              )
 ENDIF (NOT OONF_STATIC_PLUGINS)