Reworking layer2 subsystem
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 9 Jul 2013 12:10:42 +0000 (14:10 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 9 Jul 2013 12:10:42 +0000 (14:10 +0200)
Adding eth_listener

15 files changed:
cmake/cc_flags.cmake
docs/rfc5444/rfc5444_reader.txt
files/check_licences.sh
src-api/common/string.c
src-api/subsystems/oonf_layer2.c
src-api/subsystems/oonf_layer2.h
src-api/subsystems/oonf_timer.c
src-api/subsystems/oonf_timer.h
src-plugins/CMakeLists.txt
src-plugins/eth_listener/CMakeLists.txt [new file with mode: 0644]
src-plugins/eth_listener/eth_listener.c [new file with mode: 0644]
src-plugins/eth_listener/eth_listener.h [new file with mode: 0644]
src-plugins/eth_listener/ethtool-copy.h [new file with mode: 0644]
src-plugins/layer2_viewer/layer2_viewer.c
src-plugins/nl80211_listener/nl80211_listener.c

index 099d44d..f790d69 100644 (file)
@@ -83,9 +83,11 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
 
 # set release specific compiler options
+set(CMAKE_C_FLAGS "-g")
 set(CMAKE_C_FLAGS_DEBUG "-g")
 set(CMAKE_C_FLAGS_RELEASE "-O4 -g0 -DNDEBUG")
 set(CMAKE_C_FLAGS_MINSIZEREL "-Os -g0 -DNDEBUG")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG")
 
 # always add -Werror compiler options
 ADD_DEFINITIONS(-Werror)
index 31d0b4e..87e458d 100644 (file)
@@ -2,7 +2,8 @@ RFC 5444 handler library
 Copyright (c) 2010 Henning Rogge <hrogge@googlemail.com>
 
 The rfc 5444 library is a combined parser and generator for the
-'Generalized Mobile Ad Hoc Network (MANET) Packet/Message Format'.The library is split into a separate reader and writer part, both
+'Generalized Mobile Ad Hoc Network (MANET) Packet/Message Format'.
+The library is split into a separate reader and writer part, both
 of them use a generic avl-tree and double-linked list implementation.
 
 The reader and writer allow multiple independent code blocks to read
@@ -31,7 +32,7 @@ protocol in their codebase (e.g. NHDP and OLSRv2).
 **********************
 
 The basic blocks of information of rfc5444 are addresses of 1 to 16
-bytes and tlvs. TLV is a shortcut for type-length-value. Each piece
+bytes and TLVs. TLV is a shortcut for type-length-value. Each piece
 of data which is not included in packet, message or address header
 has a type and a length field, which allows a parser which does not
 know this TLV to skip to the next TLV without being forced to stop
@@ -45,7 +46,7 @@ three different levels of hierarchy in RFC 5444:
   * message TLVs
   * address TLVs
 
-Each consumer registers on one of this tree levels and can use two
+Each consumer registers on one of this three levels and can use two
 different kinds of callbacks to learn about the relevant TLV-block and
 its context. Both group of callbacks can be used in the same consumer.
 
@@ -95,8 +96,6 @@ of the reader callbacks itself!
 To parse binary rfc5444, just call rfc5444_reader_handle_packet(). 
 
 Example:
-  see example/example_reader.c:
-
   (...)
   struct rfc5444_reader *context;
 
index 8c0e726..89a042e 100755 (executable)
@@ -6,6 +6,7 @@ OKAY=0
 BAD=0
 
 EXCEPT="-not -wholename ./src-plugins/nl80211_listener/nl80211.h"
+EXCEPT="${EXCEPT} -not -wholename ./src-plugins/eth_listener/ethtool-copy.h"
 for file in $(eval find ./src* -type f -name *[.][ch] ${EXCEPT})
 do
        cmp --bytes ${LEN} ${file} ./files/default_licence.txt
index dfdbfeb..31f2873 100644 (file)
@@ -49,7 +49,7 @@
 #include "common/string.h"
 
 static const char *_get_human_readable_u64(char *out,
-    uint64_t number, const char *unit, int fraction,
+    size_t out_len, uint64_t number, const char *unit, int fraction,
     bool binary, bool raw);
 
 /**
@@ -458,7 +458,7 @@ str_get_human_readable_u64(struct human_readable_str *out,
     uint64_t number, const char *unit, int fraction,
     bool binary, bool raw) {
   return _get_human_readable_u64(
-      out->buf, number, unit, fraction, binary, raw);
+      out->buf, sizeof(*out), number, unit, fraction, binary, raw);
 }
 
 /**
@@ -483,10 +483,13 @@ str_get_human_readable_s64(struct human_readable_str *out,
     bool binary, bool raw) {
   char *outbuf = out->buf;
   uint64_t num;
+  size_t len;
 
+  len = sizeof(*out);
   if (number == INT64_MIN) {
     *outbuf++ = '-';
     num = 1ull<<63;
+    len--;
   }
   else if (number < 0) {
     num = (uint64_t)(-number);
@@ -496,7 +499,7 @@ str_get_human_readable_s64(struct human_readable_str *out,
   }
 
   return _get_human_readable_u64(
-      outbuf, num, unit, fraction, binary, raw);
+      outbuf, len, num, unit, fraction, binary, raw);
 }
 
 int
@@ -606,7 +609,7 @@ str_parse_human_readable_u64(uint64_t *dst, const char *hrn, int fraction, bool
 }
 
 static const char *
-_get_human_readable_u64(char *out,
+_get_human_readable_u64(char *out, size_t out_len,
     uint64_t number, const char *unit, int fraction,
     bool binary, bool raw) {
   static const char symbol[] = " kMGTPE";
@@ -628,7 +631,7 @@ _get_human_readable_u64(char *out,
   }
 
   /* print whole */
-  idx = snprintf(out, sizeof(*out), "%"PRIu64, number / multiplier);
+  idx = snprintf(out, out_len, "%"PRIu64, number / multiplier);
   len = idx;
 
   out[len++] = '.';
@@ -660,7 +663,7 @@ _get_human_readable_u64(char *out,
   out[idx++] = 0;
 
   if (unit) {
-    strscat(out, unit, sizeof(*out));
+    strscat(out, unit, out_len);
   }
 
   return out;
index b2acda7..4f059b3 100644 (file)
 #include "common/avl.h"
 #include "common/avl_comp.h"
 #include "common/common_types.h"
-
-#include "core/oonf_logging.h"
+#include "common/netaddr.h"
+#include "config/cfg_schema.h"
 #include "core/oonf_subsystem.h"
 #include "subsystems/oonf_class.h"
 #include "subsystems/oonf_layer2.h"
-#include "subsystems/oonf_rfc5444.h"
-#include "subsystems/oonf_timer.h"
-
-/* definitions and constants */
-#define CFG_KEY_LINKSPEED "linkspeed"
 
 /* prototypes */
 static int _init(void);
 static void _cleanup(void);
 
-static void _remove_neighbor(struct oonf_layer2_neighbor *);
-static void _remove_network(struct oonf_layer2_network *);
-static void _cb_neighbor_timeout(void *ptr);
-static void _cb_network_timeout(void *ptr);
-static int _avl_comp_l2neigh(const void *k1, const void *k2);
-static const char *_cb_get_neighbor_name(
-    struct oonf_objectkey_str *, struct oonf_class *, void *);
-static const char *_cb_get_network_name(
-    struct oonf_objectkey_str *, struct oonf_class *, void *);
-
-struct avl_tree oonf_layer2_network_id_tree;
-struct avl_tree oonf_layer2_neighbor_tree;
-
-static struct oonf_class _network_cookie = {
-  .name = "layer2 networks",
-  .size = sizeof(struct oonf_layer2_network),
-  .to_keystring = _cb_get_network_name,
-};
+static void _net_remove(struct oonf_layer2_net *l2net);
+static void _neigh_remove(struct oonf_layer2_neigh *l2neigh);
 
-static struct oonf_class _neighbor_cookie = {
-  .name = "layer2 neighbors",
-  .size = sizeof(struct oonf_layer2_neighbor),
-  .to_keystring = _cb_get_neighbor_name,
+/* subsystem definition */
+struct oonf_subsystem oonf_layer2_subsystem = {
+    .name = "layer2",
+    .init = _init,
+    .cleanup = _cleanup,
 };
 
-static struct oonf_timer_info _network_vtime_info = {
-  .name = "layer2 network vtime",
-  .callback = _cb_network_timeout,
-  .periodic = true,
+/* l2neigh string keys */
+const struct oonf_layer2_metadata oonf_layer2_metadata_neigh[OONF_LAYER2_NEIGH_COUNT] = {
+  [OONF_LAYER2_NEIGH_SIGNAL]     = { .key = OONF_LAYER2_NEIGH_SIGNAL_KEY, .unit = "dBm", .fraction = 1 },
+  [OONF_LAYER2_NEIGH_TX_BITRATE] = { .key = OONF_LAYER2_NEIGH_TX_BITRATE_KEY, .unit = "bit/s", .binary = true },
+  [OONF_LAYER2_NEIGH_RX_BITRATE] = { .key = OONF_LAYER2_NEIGH_RX_BITRATE_KEY, .unit = "bit/s", .binary = true },
+  [OONF_LAYER2_NEIGH_TX_BYTES]   = { .key = OONF_LAYER2_NEIGH_TX_BYTES_KEY, .unit = "byte", .binary = true },
+  [OONF_LAYER2_NEIGH_RX_BYTES]   = { .key = OONF_LAYER2_NEIGH_RX_BYTES_KEY, .unit = "byte", .binary = true },
+  [OONF_LAYER2_NEIGH_TX_FRAMES]  = { .key = OONF_LAYER2_NEIGH_TX_FRAMES_KEY },
+  [OONF_LAYER2_NEIGH_RX_FRAMES]  = { .key = OONF_LAYER2_NEIGH_RX_FRAMES_KEY },
+  [OONF_LAYER2_NEIGH_TX_RETRIES] = { .key = OONF_LAYER2_NEIGH_TX_RETRIES_KEY },
+  [OONF_LAYER2_NEIGH_TX_FAILED]  = { .key = OONF_LAYER2_NEIGH_TX_FAILED_KEY },
 };
 
-static struct oonf_timer_info _neighbor_vtime_info = {
-  .name = "layer2 neighbor vtime",
-  .callback = _cb_neighbor_timeout,
-  .periodic = true,
+const struct oonf_layer2_metadata oonf_layer2_metadata_net[OONF_LAYER2_NET_COUNT] = {
+  [OONF_LAYER2_NET_FREQUENCY]    = { .key = OONF_LAYER2_NET_FREQUENCY_KEY, .unit = "Hz" },
+  [OONF_LAYER2_NET_MAX_BITRATE]  = { .key = OONF_LAYER2_NET_MAX_BITRATE_KEY, .unit = "bit/s", .binary = true },
 };
 
-struct oonf_subsystem oonf_layer2_subsystem = {
-  .name = "layer2",
-  .init = _init,
-  .cleanup = _cleanup,
+/* infrastructure for l2net/l2neigh tree */
+static struct oonf_class _l2network_class = {
+  .name = LAYER2_CLASS_NETWORK,
+  .size = sizeof(struct oonf_layer2_net),
 };
+static struct oonf_class _l2neighbor_class = {
+  .name = LAYER2_CLASS_NEIGHBOR,
+  .size = sizeof(struct oonf_layer2_neigh),
+};
+
+struct avl_tree oonf_layer2_net_tree;
+
+static uint32_t _next_origin = 0;
 
 /**
- * Initialize layer2 subsystem
+ * Subsystem constructor
  * @return always returns 0
  */
 static int
 _init(void) {
-  oonf_class_add(&_network_cookie);
-  oonf_class_add(&_neighbor_cookie);
+  oonf_class_add(&_l2network_class);
+  oonf_class_add(&_l2neighbor_class);
 
-  oonf_timer_add(&_network_vtime_info);
-  oonf_timer_add(&_neighbor_vtime_info);
-
-  avl_init(&oonf_layer2_network_id_tree, avl_comp_netaddr, false);
-  avl_init(&oonf_layer2_neighbor_tree, _avl_comp_l2neigh, false);
+  avl_init(&oonf_layer2_net_tree, avl_comp_netaddr, false);
   return 0;
 }
 
 /**
- * Cleanup all resources allocated by layer2 subsystem
+ * Subsystem destructor
  */
 static void
 _cleanup(void) {
-  struct oonf_layer2_neighbor *neigh, *neigh_it;
-  struct oonf_layer2_network *net, *net_it;
+  struct oonf_layer2_net *l2net, *l2n_it;
 
-  avl_for_each_element_safe(&oonf_layer2_network_id_tree, net, _id_node, net_it) {
-    net->active = false;
-    oonf_layer2_remove_network(net);
+  avl_for_each_element_safe(&oonf_layer2_net_tree, l2net, _node, l2n_it) {
+    _net_remove(l2net);
   }
 
-  avl_for_each_element_safe(&oonf_layer2_neighbor_tree, neigh, _node, neigh_it) {
-    neigh->active = false;
-    oonf_layer2_remove_neighbor(neigh);
-  }
-
-  oonf_timer_remove(&_network_vtime_info);
-  oonf_timer_remove(&_neighbor_vtime_info);
-  oonf_class_remove(&_network_cookie);
-  oonf_class_remove(&_neighbor_cookie);
+  oonf_class_remove(&_l2neighbor_class);
+  oonf_class_remove(&_l2network_class);
 }
 
 /**
- * Add an active network to the database. If an entry for the
- * interface does already exists, it will be returned by this
- * function and no new entry will be created.
- * @param radio_id ID of the radio (might be NULL)
- * @param if_index local interface index of network
- * @param name interface name of the radio (might be NULL)
- * @param vtime validity time of data
- * @return pointer to layer2 network data, NULL if OOM
+ * Register a new originator number for layer2 data
+ * @return originator number
  */
-struct oonf_layer2_network *
-oonf_layer2_add_network(struct netaddr *radio_id, uint32_t if_index,
-    uint64_t vtime) {
-  struct oonf_layer2_network *net;
-
-  net = oonf_layer2_get_network_by_id(radio_id);
-  if (!net) {
-    net = oonf_class_malloc(&_network_cookie);
-    if (!net) {
-      return NULL;
-    }
-
-    /* initialize the nodes */
-    net->_id_node.key = &net->radio_id;
-    memcpy (&net->radio_id, radio_id, sizeof(*radio_id));
-    avl_insert(&oonf_layer2_network_id_tree, &net->_id_node);
-
-    net->if_index = if_index;
-    net->_valitity_timer.info = &_network_vtime_info;
-    net->_valitity_timer.cb_context = net;
-
-    oonf_class_event(&_network_cookie, net, OONF_OBJECT_ADDED);
-  }
-
-  OONF_DEBUG(LOG_LAYER2, "Reset validity of network timer: %"PRIu64,
-      vtime);
-  net->active = true;
-  oonf_timer_set(&net->_valitity_timer, vtime);
-  return net;
+uint32_t
+oonf_layer2_register_origin(void) {
+  _next_origin++;
+  return _next_origin;
 }
 
 /**
- * Remove a layer2 network from the database
- * @param net pointer to layer2 network data
+ * Unregister an originator number and remove all layer2 data associated
+ * with this originator
+ * @param origin originator number
  */
 void
-oonf_layer2_remove_network(struct oonf_layer2_network *net) {
-  if (net->active) {
-    /* restart validity timer */
-    oonf_timer_set(&net->_valitity_timer,
-      oonf_timer_get_period(&net->_valitity_timer));
+oonf_layer2_unregister_origin(uint32_t origin) {
+  struct oonf_layer2_net *l2net, *l2net_it;
+
+  avl_for_each_element_safe(&oonf_layer2_net_tree, l2net, _node, l2net_it) {
+    oonf_layer2_net_remove(l2net, origin);
   }
-  _remove_network(net);
 }
 
 /**
- * Retrieve a layer2 neighbor from the database
- * @param radio_id pointer to radio_id of network
- * @param neigh_mac pointer to layer2 address of neighbor
- * @return pointer to layer2 neighbor data, NULL if not found
+ * Add a layer-2 addr to the database
+ * @param addr local mac address of addr
+ * @return layer-2 addr object
  */
-struct oonf_layer2_neighbor *
-oonf_layer2_get_neighbor(struct netaddr *radio_id, struct netaddr *neigh_mac) {
-  struct oonf_layer2_neighbor_key key;
-  struct oonf_layer2_neighbor *neigh;
-
-  key.radio_mac = *radio_id;
-  key.neighbor_mac = *neigh_mac;
+struct oonf_layer2_net *
+oonf_layer2_net_add(struct netaddr *network) {
+  struct oonf_layer2_net *l2net;
 
-  return avl_find_element(&oonf_layer2_neighbor_tree, &key, neigh, _node);
-}
+  l2net = avl_find_element(&oonf_layer2_net_tree, network, l2net, _node);
+  if (l2net) {
+    return l2net;
+  }
 
-/**
- * Add a layer2 neighbor to the database. If an entry for the
- * neighbor on the interface does already exists, it will be
- * returned by this function and no new entry will be created.
- * @param radio_id pointer to radio_id of network
- * @param neigh_mac layer2 address of neighbor
- * @param if_index local interface index of the neighbor
- * @param vtime validity time of data
- * @return pointer to layer2 neighbor data, NULL if OOM
- */
-struct oonf_layer2_neighbor *
-oonf_layer2_add_neighbor(struct netaddr *radio_id, struct netaddr *neigh_mac,
-    uint32_t if_index, uint64_t vtime) {
-  struct oonf_layer2_neighbor *neigh;
-
-  assert (vtime > 0);
-
-  neigh = oonf_layer2_get_neighbor(radio_id, neigh_mac);
-  if (!neigh) {
-    neigh = oonf_class_malloc(&_neighbor_cookie);
-    if (!neigh) {
-      return NULL;
-    }
+  l2net = oonf_class_malloc(&_l2network_class);
+  if (!l2net) {
+    return NULL;
+  }
 
-    neigh->if_index = if_index;
-    memcpy(&neigh->key.radio_mac, radio_id, sizeof(*radio_id));
-    memcpy(&neigh->key.neighbor_mac, neigh_mac, sizeof(*neigh_mac));
+  memcpy(&l2net->addr, network, sizeof(*network));
+  l2net->_node.key = &l2net->addr;
+  avl_insert(&oonf_layer2_net_tree, &l2net->_node);
 
-    neigh->_node.key = &neigh->key;
-    neigh->_valitity_timer.info = &_neighbor_vtime_info;
-    neigh->_valitity_timer.cb_context = neigh;
+  avl_init(&l2net->neighbors, avl_comp_netaddr, false);
+  avl_init(&l2net->_ip_defaults, avl_comp_netaddr, false);
 
-    avl_insert(&oonf_layer2_neighbor_tree, &neigh->_node);
-    oonf_class_event(&_neighbor_cookie, neigh, OONF_OBJECT_ADDED);
-  }
+  oonf_class_event(&_l2network_class, l2net, OONF_OBJECT_ADDED);
 
-  neigh->active = true;
-  oonf_timer_set(&neigh->_valitity_timer, vtime);
-  return neigh;
+  return l2net;
 }
 
 /**
- * Remove a layer2 neighbor from the database
- * @param neigh pointer to layer2 neighbor
+ * Remove all information of a certain originator from a layer-2 addr
+ * object. Remove the object if its empty and has no neighbors anymore.
+ * @param l2net layer-2 addr object
+ * @param origin originator number
  */
 void
-oonf_layer2_remove_neighbor(struct oonf_layer2_neighbor *neigh) {
-  if (neigh->active) {
-    /* restart validity timer */
-    oonf_timer_set(&neigh->_valitity_timer,
-        oonf_timer_get_period(&neigh->_valitity_timer));
+oonf_layer2_net_remove(struct oonf_layer2_net *l2net, uint32_t origin) {
+  struct oonf_layer2_neigh *l2neigh, *l2neigh_it;
+  int i;
+
+  avl_for_each_element_safe(&l2net->neighbors, l2neigh, _node, l2neigh_it) {
+    oonf_layer2_neigh_remove(l2neigh, origin);
+  }
+
+  for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
+    if (l2net->data[i]._origin == origin) {
+      oonf_layer2_reset_value(&l2net->data[i]);
+    }
   }
-  _remove_neighbor(neigh);
+  oonf_layer2_net_commit(l2net);
 }
 
 /**
- * Set a new list of supported rates. Data will not be changed if an
- * error happens.
- * @param net pointer to layer2 network
- * @param rate_array pointer to array of supported rates
- * @param rate_count number of supported rates
- * @return -1 if an out of memory error happened, 0 otherwise.
+ * Commit all changes to a layer-2 addr object. This might remove the
+ * object from the database if all data has been removed from the object.
+ * @param l2net layer-2 addr object
+ * @return true if the object has been removed, false otherwise
  */
-int
-oonf_layer2_network_set_supported_rates(struct oonf_layer2_network *net,
-    uint64_t *rate_array, size_t rate_count) {
-  uint64_t *rates;
-
-  rates = realloc(net->supported_rates, rate_count * sizeof(uint64_t));
-  if (rates == NULL) {
-    return -1;
+bool
+oonf_layer2_net_commit(struct oonf_layer2_net *l2net) {
+  size_t i;
+
+  if (l2net->neighbors.count > 0) {
+    oonf_class_event(&_l2network_class, l2net, OONF_OBJECT_CHANGED);
+    return false;
   }
 
-  net->_available_data |= OONF_L2NET_SUPPORTED_RATES;
-  net->supported_rates = rates;
-  net->rate_count = rate_count;
-  memcpy(rates, rate_array, sizeof(uint64_t) * rate_count);
+  for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
+    if (oonf_layer2_has_value(&l2net->data[i])) {
+      oonf_class_event(&_l2network_class, l2net, OONF_OBJECT_CHANGED);
+      return false;
+    }
+  }
 
-  return 0;
+  _net_remove(l2net);
+  return true;
 }
 
 /**
- * Triggers a change callback for a layer2 neighbor
- * @param neigh pointer to layer2 neighbor
+ * Add a layer-2 neighbor to a addr.
+ * @param l2net layer-2 addr object
+ * @param neigh mac address of layer-2 neighbor
+ * @return layer-2 neighbor object
  */
-void
-oonf_layer2_neighbor_commit(struct oonf_layer2_neighbor *neigh) {
-  oonf_class_event(&_neighbor_cookie, neigh, OONF_OBJECT_CHANGED);
-}
+struct oonf_layer2_neigh *
+oonf_layer2_neigh_add(struct oonf_layer2_net *l2net,
+    struct netaddr *neigh) {
+  struct oonf_layer2_neigh *l2neigh;
+
+  if (netaddr_get_address_family(neigh) != AF_MAC48
+      && netaddr_get_address_family(neigh) != AF_EUI64) {
+    return NULL;
+  }
 
-/**
- * Triggers a change callback for a layer2 network
- * @param net pointer to layer2 network
- */
-void
-oonf_layer2_network_commit(struct oonf_layer2_network *net) {
-  oonf_class_event(&_network_cookie, net, OONF_OBJECT_CHANGED);
-}
+  l2neigh = oonf_layer2_neigh_get(l2net, neigh);
+  if (l2neigh) {
+    return l2neigh;
+  }
 
-/**
- * Remove a layer2 neighbor from the database
- * @param neigh pointer to layer2 neighbor
- */
-static void
-_remove_neighbor(struct oonf_layer2_neighbor *neigh) {
-  if (neigh->active) {
-    oonf_class_event(&_neighbor_cookie, neigh, OONF_OBJECT_REMOVED);
-    neigh->active = false;
-    return;
+  l2neigh = oonf_class_malloc(&_l2neighbor_class);
+  if (!l2neigh) {
+    return NULL;
   }
-  avl_remove(&oonf_layer2_neighbor_tree, &neigh->_node);
-  oonf_timer_stop(&neigh->_valitity_timer);
-  oonf_class_free(&_neighbor_cookie, neigh);
-}
 
-/**
- * Remove a layer2 network from the database
- * @param net pointer to layer2 network data
- */
-static void
-_remove_network(struct oonf_layer2_network *net) {
-  if (net->active) {
-    oonf_class_event(&_network_cookie, net, OONF_OBJECT_REMOVED);
-    net->active = false;
-    return;
+  memcpy(&l2neigh->addr, neigh, sizeof(*neigh));
+  l2neigh->_node.key = &l2neigh->addr;
+  l2neigh->network = l2net;
+
+  avl_insert(&l2net->neighbors, &l2neigh->_node);
+
+  if (netaddr_get_address_family(neigh) == AF_MAC48
+      || netaddr_get_address_family(neigh) == AF_EUI64) {
+    /* initialize ring for IP addresses of neighbor */
+    list_init_head(&l2neigh->_neigh_ring);
   }
 
-  avl_remove(&oonf_layer2_network_id_tree, &net->_id_node);
+  oonf_class_event(&_l2neighbor_class, l2neigh, OONF_OBJECT_ADDED);
 
-  oonf_timer_stop(&net->_valitity_timer);
-  free (net->supported_rates);
-  oonf_class_free(&_network_cookie, net);
+  return l2neigh;
 }
 
 /**
- * Validity time callback for neighbor entries
- * @param ptr pointer to neighbor entry
+ * Remove all information of a certain originator from a layer-2 neighbor
+ * object. Remove the object if its empty.
+ * @param l2neigh layer-2 neighbor object
+ * @param origin originator number
  */
-static void
-_cb_neighbor_timeout(void *ptr) {
-#ifdef OONF_LOG_DEBUG_INFO
-  struct oonf_layer2_neighbor *neigh = ptr;
-#endif
-  OONF_DEBUG(LOG_LAYER2, "Layer-2 neighbor timeout (was %sactive)", neigh->active ? "" : "in");
-  _remove_neighbor(ptr);
+void
+oonf_layer2_neigh_remove(struct oonf_layer2_neigh *l2neigh, uint32_t origin) {
+  int i;
+
+  for (i=0; i<OONF_LAYER2_NEIGH_COUNT; i++) {
+    if (l2neigh->data[i]._origin == origin) {
+      oonf_layer2_reset_value(&l2neigh->data[i]);
+    }
+  }
+  oonf_layer2_neigh_commit(l2neigh);
 }
 
 /**
- * Validity time callback for network entries
- * @param ptr pointer to network entry
+ * Commit all changes to a layer-2 neighbor object. This might remove the
+ * object from the database if all data has been removed from the object.
+ * @param l2neigh layer-2 neighbor object
+ * @return true if the object has been removed, false otherwise
  */
-static void
-_cb_network_timeout(void *ptr) {
-#ifdef OONF_LOG_DEBUG_INFO
-  struct oonf_layer2_network *net = ptr;
-#endif
-  OONF_DEBUG(LOG_LAYER2, "Layer-2 network timeout (was %sactive)", net->active ? "" : "in");
-  _remove_network(ptr);
+bool
+oonf_layer2_neigh_commit(struct oonf_layer2_neigh *l2neigh) {
+  size_t i;
+
+  for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
+    if (oonf_layer2_has_value(&l2neigh->data[i])) {
+      oonf_class_event(&_l2neighbor_class, l2neigh, OONF_OBJECT_CHANGED);
+      return false;
+    }
+  }
+
+  _neigh_remove(l2neigh);
+  return true;
 }
 
-/**
- * AVL comparator for layer2 neighbor nodes
- * @param k1 pointer to first layer2 neighbor
- * @param k2 pointer to second layer2 neighbor
- * @param ptr unused
- * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
- */
-static int
-_avl_comp_l2neigh(const void *k1, const void *k2) {
-  const struct oonf_layer2_neighbor_key *key1, *key2;
-  int result;
+const struct oonf_layer2_data *
+oonf_layer2_neigh_query(const struct netaddr *l2net_addr,
+    const struct netaddr *l2neigh_addr, enum oonf_layer2_neighbor_index idx) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_layer2_neigh *l2neigh;
+  struct oonf_layer2_data *data;
+
+  /* query layer2 database about neighbor */
+  l2net = oonf_layer2_net_get(l2net_addr);
+  if (l2net == NULL) {
+    return 0;
+  }
 
-  key1 = k1;
-  key2 = k2;
+  l2neigh = oonf_layer2_neigh_get(l2net, l2neigh_addr);
+  if (l2neigh == NULL) {
+    data = &l2neigh->data[idx];
+    if (oonf_layer2_has_value(data)) {
+      return data;
+    }
+  }
 
-  result = netaddr_cmp(&key1->radio_mac, &key2->radio_mac);
-  if (!result) {
-    result = netaddr_cmp(&key1->neighbor_mac, &key2->neighbor_mac);
+  data = &l2neigh->network->neighdata[idx];
+  if (oonf_layer2_has_value(data)) {
+    return data;
   }
-  return result;
+  return NULL;
 }
 
 /**
- * Construct human readable object id of neighbor for callbacks
- * @param buf pointer to key output buffer
- * @param cl pointer to class
- * @param ptr pointer to l2 neighbor
- * @return pointer to id
+ * Removes a layer-2 addr object from the database.
+ * @param l2net layer-2 addr object
  */
-static const char *
-_cb_get_neighbor_name(struct oonf_objectkey_str *buf,
-    struct oonf_class *cl, void *ptr) {
-  struct netaddr_str nbuf1, nbuf2;
-  struct oonf_layer2_neighbor *nbr;
-
-  nbr = ptr;
-
-  snprintf(buf->buf, sizeof(*buf), "%s::neigh=%s/radio=%s",
-      cl->name,
-      netaddr_to_string(&nbuf1, &nbr->key.neighbor_mac),
-      netaddr_to_string(&nbuf2, &nbr->key.radio_mac));
-  return buf->buf;
+static void
+_net_remove(struct oonf_layer2_net *l2net) {
+  struct oonf_layer2_neigh *l2neigh, *l2n_it;
+
+  /* free all embedded neighbors */
+  avl_for_each_element_safe(&l2net->neighbors, l2neigh, _node, l2n_it) {
+    _neigh_remove(l2neigh);
+  }
+
+  oonf_class_event(&_l2network_class, l2net, OONF_OBJECT_REMOVED);
+
+  /* free addr */
+  avl_remove(&oonf_layer2_net_tree, &l2net->_node);
+  oonf_class_free(&_l2network_class, l2net);
 }
 
 /**
- * Construct human readable object id of network for callbacks
- * @param buf pointer to key output buffer
- * @param cl pointer to class
- * @param ptr pointer to l2 neighbor
- * @return pointer to id
+ * Removes a layer-2 neighbor object from the database
+ * @param l2neigh layer-2 neighbor object
  */
-static const char *
-_cb_get_network_name(struct oonf_objectkey_str *buf,
-    struct oonf_class *cl, void *ptr) {
-  struct netaddr_str buf1;
-  struct oonf_layer2_network *net;
+static void
+_neigh_remove(struct oonf_layer2_neigh *l2neigh) {
+  struct oonf_layer2_neigh *neigh, *n_it;
 
-  net = ptr;
+  /* inform user that mac entry will be removed */
+  oonf_class_event(&_l2neighbor_class, l2neigh, OONF_OBJECT_REMOVED);
+
+  /* remove all connected IP defaults */
+  list_for_each_element_safe(&l2neigh->_neigh_ring, neigh, _neigh_ring, n_it) {
+    list_remove(&neigh->_neigh_ring);
+  }
 
-  snprintf(buf->buf, sizeof(*buf), "%s::radio=%s",
-      cl->name, netaddr_to_string(&buf1, &net->radio_id));
-  return buf->buf;
+  /* free resources for mac entry */
+  avl_remove(&l2neigh->network->neighbors, &l2neigh->_node);
+  oonf_class_free(&_l2neighbor_class, l2neigh);
 }
index 3e1ab2b..bb44a2c 100644 (file)
 
 #include "common/avl.h"
 #include "common/common_types.h"
-#include "common/netaddr.h"
-
-#include "subsystems/oonf_clock.h"
+#include "core/oonf_subsystem.h"
 #include "subsystems/oonf_timer.h"
 
-/* both callbacks support ADD and REMOVE events */
-#define LAYER2_CLASS_NEIGHBOR           "layer2_neighbor"
-#define LAYER2_CLASS_NETWORK            "layer2_neighbor"
-
-enum oonf_layer2_neighbor_data {
-  OONF_L2NEIGH_SIGNAL = 1<<0,
-  OONF_L2NEIGH_LAST_SEEN = 1<<1,
-  OONF_L2NEIGH_RX_BITRATE = 1<<2,
-  OONF_L2NEIGH_RX_BYTES = 1<<3,
-  OONF_L2NEIGH_RX_PACKETS = 1<<4,
-  OONF_L2NEIGH_TX_BITRATE = 1<<5,
-  OONF_L2NEIGH_TX_BYTES = 1<<6,
-  OONF_L2NEIGH_TX_PACKETS = 1<<7,
-  OONF_L2NEIGH_TX_RETRIES = 1<<8,
-  OONF_L2NEIGH_TX_FAILED = 1<<9,
+#define LAYER2_CLASS_NEIGHBOR  "layer2_neighbor"
+#define LAYER2_CLASS_NETWORK   "layer2_network"
+
+#define OONF_LAYER2_NET_MAX_BITRATE_KEY  "max_bitrate"
+#define OONF_LAYER2_NET_FREQUENCY_KEY    "frequency"
+
+#define OONF_LAYER2_NEIGH_SIGNAL_KEY     "signal"
+#define OONF_LAYER2_NEIGH_TX_BITRATE_KEY "tx_bitrate"
+#define OONF_LAYER2_NEIGH_RX_BITRATE_KEY "rx_bitrate"
+#define OONF_LAYER2_NEIGH_TX_BYTES_KEY   "tx_bytes"
+#define OONF_LAYER2_NEIGH_RX_BYTES_KEY   "rx_bytes"
+#define OONF_LAYER2_NEIGH_TX_FRAMES_KEY  "tx_frames"
+#define OONF_LAYER2_NEIGH_RX_FRAMES_KEY  "rx_frames"
+#define OONF_LAYER2_NEIGH_TX_RETRIES_KEY "tx_retries"
+#define OONF_LAYER2_NEIGH_TX_FAILED_KEY  "tx_failed"
+
+struct oonf_layer2_data {
+  int64_t _value;
+  bool _has_value;
+  uint32_t _origin;
 };
 
-struct oonf_layer2_neighbor_key {
-  struct netaddr neighbor_mac;
-  struct netaddr radio_mac;
+enum oonf_layer2_network_index {
+  OONF_LAYER2_NET_FREQUENCY,
+  OONF_LAYER2_NET_MAX_BITRATE,
+
+  /* last entry */
+  OONF_LAYER2_NET_COUNT,
 };
 
-struct oonf_layer2_neighbor {
-  struct avl_node _node;
-  struct oonf_layer2_neighbor_key key;
-  uint32_t if_index;
+enum oonf_layer2_network_type {
+  OONF_LAYER2_TYPE_UNDEFINED,
+  OONF_LAYER2_TYPE_WIRELESS,
+  OONF_LAYER2_TYPE_ETHERNET,
+  OONF_LAYER2_TYPE_TUNNEL,
+};
 
-  bool active;
+enum oonf_layer2_neighbor_index {
+  OONF_LAYER2_NEIGH_SIGNAL,
+  OONF_LAYER2_NEIGH_TX_BITRATE,
+  OONF_LAYER2_NEIGH_RX_BITRATE,
+  OONF_LAYER2_NEIGH_TX_BYTES,
+  OONF_LAYER2_NEIGH_RX_BYTES,
+  OONF_LAYER2_NEIGH_TX_FRAMES,
+  OONF_LAYER2_NEIGH_RX_FRAMES,
+  OONF_LAYER2_NEIGH_TX_RETRIES,
+  OONF_LAYER2_NEIGH_TX_FAILED,
+
+  /* last entry */
+  OONF_LAYER2_NEIGH_COUNT,
+};
 
-  struct oonf_timer_entry _valitity_timer;
-  enum oonf_layer2_neighbor_data _available_data;
+struct oonf_layer2_net {
+  struct avl_node _node;
+  struct netaddr addr;
 
-  int16_t signal_dbm;
-  uint64_t last_seen;
+  int  if_index;
+  char if_name[IF_NAMESIZE];
+  char if_ident[64];
+  enum oonf_layer2_network_type if_type;
 
-  uint64_t tx_bitrate, rx_bitrate;
-  uint32_t tx_bytes, tx_packets;
-  uint32_t rx_bytes, rx_packets;
+  struct avl_tree neighbors;
+  struct avl_tree _ip_defaults;
 
-  uint32_t tx_retries, tx_failed;
-};
+  uint64_t last_seen;
 
-enum oonf_layer2_network_data {
-  OONF_L2NET_SSID = 1<<0,
-  OONF_L2NET_LAST_SEEN = 1<<1,
-  OONF_L2NET_FREQUENCY = 1<<2,
-  OONF_L2NET_SUPPORTED_RATES = 1<<3,
+  struct oonf_layer2_data data[OONF_LAYER2_NET_COUNT];
+  struct oonf_layer2_data neighdata[OONF_LAYER2_NEIGH_COUNT];
 };
 
-struct oonf_layer2_network {
-  struct avl_node _id_node;
-
-  struct netaddr radio_id;
-  uint32_t if_index;
-
-  bool active;
+struct oonf_layer2_neigh {
+  struct avl_node _node;
+  struct netaddr addr;
 
-  struct oonf_timer_entry _valitity_timer;
-  enum oonf_layer2_network_data _available_data;
+  struct list_entity _neigh_ring;
 
-  /* 0-terminated ssid string */
-  char ssid[33];
+  struct oonf_layer2_net *network;
 
   uint64_t last_seen;
 
-  uint64_t frequency;
-
-  uint64_t *supported_rates;
-  size_t rate_count;
+  struct oonf_layer2_data data[OONF_LAYER2_NEIGH_COUNT];
 };
 
-struct oonf_layer2_network_config {
-  struct avl_node _name_node;
-
-  const char *if_name;
-
-  uint64_t tx_bitrate;
+struct oonf_layer2_metadata {
+  const char key[16];
+  const char unit[8];
+  const int fraction;
+  const bool binary;
 };
 
 #define LOG_LAYER2 oonf_layer2_subsystem.logging
 EXPORT extern struct oonf_subsystem oonf_layer2_subsystem;
 
-EXPORT extern struct avl_tree oonf_layer2_network_id_tree;
-EXPORT extern struct avl_tree oonf_layer2_network_name_tree;
-EXPORT extern struct avl_tree oonf_layer2_neighbor_tree;
-
-EXPORT struct oonf_layer2_network *oonf_layer2_add_network(
-    struct netaddr *ssid, uint32_t if_index, uint64_t vtime);
-EXPORT void oonf_layer2_remove_network(struct oonf_layer2_network *);
-
-EXPORT struct oonf_layer2_neighbor *oonf_layer2_get_neighbor(
-    struct netaddr *radio_id, struct netaddr *neigh_mac);
-EXPORT struct oonf_layer2_neighbor *oonf_layer2_add_neighbor(
-    struct netaddr *radio_id, struct netaddr *neigh_mac,
-    uint32_t if_index, uint64_t vtime);
-EXPORT void oonf_layer2_remove_neighbor(struct oonf_layer2_neighbor *);
-
-EXPORT int oonf_layer2_network_set_supported_rates(
-    struct oonf_layer2_network *net,
-    uint64_t *rate_array, size_t rate_count);
+EXPORT extern const struct oonf_layer2_metadata oonf_layer2_metadata_neigh[OONF_LAYER2_NEIGH_COUNT];
+EXPORT extern const struct oonf_layer2_metadata oonf_layer2_metadata_net[OONF_LAYER2_NET_COUNT];
 
-EXPORT void oonf_layer2_neighbor_commit(struct oonf_layer2_neighbor *);
-EXPORT void oonf_layer2_network_commit(struct oonf_layer2_network *);
+EXPORT extern struct avl_tree oonf_layer2_net_tree;
 
-/**
- * Retrieve a layer2 network entry from the database
- * @param radio mac address of the local interface
- * @return pointer to layer2 network, NULL if not found
- */
-static INLINE struct oonf_layer2_network *
-oonf_layer2_get_network_by_id(struct netaddr *radio) {
-  struct oonf_layer2_network *net;
-  return avl_find_element(&oonf_layer2_network_id_tree, radio, net, _id_node);
-}
+EXPORT uint32_t oonf_layer2_register_origin(void);
+EXPORT void oonf_layer2_unregister_origin(uint32_t);
 
-/*
- * The following inline functions should be used to set and test for
- * data in the layer 2 neighbor and network data. Reading can be done
- * by directly accessing the data fields (after testing if they contain
- * data at all).
- */
+EXPORT struct oonf_layer2_net *oonf_layer2_net_add(struct netaddr *);
+EXPORT void oonf_layer2_net_remove(
+    struct oonf_layer2_net *, uint32_t origin);
+EXPORT bool oonf_layer2_net_commit(struct oonf_layer2_net *);
 
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains signal strength, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_signal(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_SIGNAL) != 0;
-}
+EXPORT struct oonf_layer2_neigh *oonf_layer2_neigh_add(
+    struct oonf_layer2_net *, struct netaddr *l2neigh);
+EXPORT void oonf_layer2_neigh_remove(
+    struct oonf_layer2_neigh *l2neigh, uint32_t origin);
+EXPORT bool oonf_layer2_neigh_commit(struct oonf_layer2_neigh *l2neigh);
 
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains timestamp
- *    when station has been seen last, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_last_seen(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_LAST_SEEN) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains rx bitrate, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_rx_bitrate(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_RX_BITRATE) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains rx bytes, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_rx_bytes(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_RX_BYTES) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains rx packets, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_rx_packets(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_RX_PACKETS) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains tx bitrate, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_tx_bitrate(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_TX_BITRATE) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains tx bytes, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_tx_bytes(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_TX_BYTES) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains tx packets, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_tx_packets(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_TX_PACKETS) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains tx retries, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_tx_retries(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_TX_RETRIES) != 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @return true if data contains tx failed, false otherwise
- */
-static INLINE bool
-oonf_layer2_neighbor_has_tx_failed(struct oonf_layer2_neighbor *neigh) {
-  return (neigh->_available_data & OONF_L2NEIGH_TX_FAILED) != 0;
-}
-
-/**
- * Clear all optional data from a layer2 neighbor
- * @param neigh pointer to layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_clear(struct oonf_layer2_neighbor *neigh) {
-  neigh->_available_data = 0;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param signal_dbm signal strength to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_signal(struct oonf_layer2_neighbor *neigh, int16_t signal_dbm) {
-  neigh->_available_data |= OONF_L2NEIGH_SIGNAL;
-  neigh->signal_dbm = signal_dbm;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param relative relative time since station was last seen
- *   to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_last_seen(struct oonf_layer2_neighbor *neigh, int64_t relative) {
-  neigh->_available_data |= OONF_L2NEIGH_LAST_SEEN;
-  neigh->last_seen = oonf_clock_get_absolute(-relative);
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param bitrate incoming bitrate of station to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_rx_bitrate(struct oonf_layer2_neighbor *neigh, uint64_t bitrate) {
-  neigh->_available_data |= OONF_L2NEIGH_RX_BITRATE;
-  neigh->rx_bitrate = bitrate;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param bytes total number of bytes received by station
- *    to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_rx_bytes(struct oonf_layer2_neighbor *neigh, uint32_t bytes) {
-  neigh->_available_data |= OONF_L2NEIGH_RX_BYTES;
-  neigh->rx_bytes = bytes;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param packets total number of packets received by station
- *    to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_rx_packets(struct oonf_layer2_neighbor *neigh, uint32_t packets) {
-  neigh->_available_data |= OONF_L2NEIGH_RX_PACKETS;
-  neigh->rx_packets = packets;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param bytes outgoing bitrate of station
- *    to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_tx_bitrate(struct oonf_layer2_neighbor *neigh, uint64_t bitrate) {
-  neigh->_available_data |= OONF_L2NEIGH_TX_BITRATE;
-  neigh->tx_bitrate = bitrate;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param bytes total number of bytes sent to station
- *    to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_tx_bytes(struct oonf_layer2_neighbor *neigh, uint32_t bytes) {
-  neigh->_available_data |= OONF_L2NEIGH_TX_BYTES;
-  neigh->tx_bytes = bytes;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param packets total number of packwets sent to station
- *    to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_tx_packets(struct oonf_layer2_neighbor *neigh, uint32_t packets) {
-  neigh->_available_data |= OONF_L2NEIGH_TX_PACKETS;
-  neigh->tx_packets = packets;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param retries total number of transmission retries to station
- *   to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_tx_retries(struct oonf_layer2_neighbor *neigh, uint32_t retries) {
-  neigh->_available_data |= OONF_L2NEIGH_TX_PACKETS;
-  neigh->tx_retries = retries;
-}
-
-/**
- * @param neigh pointer to layer2 neighbor data
- * @param signal_dbm signal strength to store in layer2 neighbor data
- */
-static INLINE void
-oonf_layer2_neighbor_set_tx_fails(struct oonf_layer2_neighbor *neigh, uint32_t failed) {
-  neigh->_available_data |= OONF_L2NEIGH_TX_PACKETS;
-  neigh->tx_failed = failed;
-}
-
-/**
- * @param neigh pointer to layer2 network data
- * @return true if data contains bssid of network, false otherwise
- */
-static INLINE bool
-oonf_layer2_network_has_ssid(struct oonf_layer2_network *net) {
-  return (net->_available_data & OONF_L2NET_SSID) != 0;
-}
+EXPORT const struct oonf_layer2_data *oonf_layer2_neigh_query(
+    const struct netaddr *l2net, const struct netaddr *l2neigh,
+    enum oonf_layer2_neighbor_index idx);
 
 /**
- * @param neigh pointer to layer2 network data
- * @return true if data contains timestamp when network
- *    has been seen last, false otherwise
+ * Get a layer-2 addr object from the database
+ * @param addr local mac address of addr
+ * @return layer-2 addr object, NULL if not found
  */
-static INLINE bool
-oonf_layer2_network_has_last_seen(struct oonf_layer2_network *net) {
-  return (net->_available_data & OONF_L2NET_LAST_SEEN) != 0;
+static inline struct oonf_layer2_net *
+oonf_layer2_net_get(const struct netaddr *addr) {
+  struct oonf_layer2_net *l2net;
+  return avl_find_element(&oonf_layer2_net_tree, addr, l2net, _node);
 }
 
 /**
- * @param neigh pointer to layer2 network data
- * @return true if data contains signal strength, false otherwise
+ * Get a layer-2 neighbor object from the database
+ * @param l2net layer-2 addr object
+ * @param addr remote mac address of neighbor
+ * @return layer-2 neighbor object, NULL if not found
  */
-static INLINE bool
-oonf_layer2_network_has_frequency(struct oonf_layer2_network *net) {
-  return (net->_available_data & OONF_L2NET_FREQUENCY) != 0;
+static inline struct oonf_layer2_neigh *
+oonf_layer2_neigh_get(const struct oonf_layer2_net *l2net,
+    const struct netaddr *addr) {
+  struct oonf_layer2_neigh *l2neigh;
+  return avl_find_element(&l2net->neighbors, addr, l2neigh, _node);
 }
 
 /**
- * @param neigh pointer to layer2 network data
- * @return true if data contains supported data-rates, false otherwise
+ * @param l2data layer-2 data object
+ * @return true if object contains a value, false otherwise
  */
-static INLINE bool
-oonf_layer2_network_has_supported_rates(struct oonf_layer2_network *net) {
-  return (net->_available_data & OONF_L2NET_SUPPORTED_RATES) != 0;
+static inline bool
+oonf_layer2_has_value(const struct oonf_layer2_data *l2data) {
+  return l2data->_has_value;
 }
 
 /**
- * Clear all optional data from a layer2 neighbor
- * @param neigh pointer to layer2 neighbor data
+ * @param l2data layer-2 data object
+ * @return value of data object
  */
-static INLINE void
-oonf_layer2_network_clear(struct oonf_layer2_network *net) {
-  net->_available_data = 0;
+static inline int64_t
+oonf_layer2_get_value(const struct oonf_layer2_data *l2data) {
+  return l2data->_value;
 }
 
 /**
- * @param neigh pointer to layer2 network data
- * @param bssid bssid to store in layer2 network data
+ * @param l2data layer-2 data object
+ * @return originator of data value
  */
-static INLINE void
-oonf_layer2_network_set_ssid(struct oonf_layer2_network *net, char *ssid) {
-  net->_available_data |= OONF_L2NET_SSID;
-  strscpy(net->ssid, ssid, sizeof(net->ssid));
+static inline uint32_t
+oonf_layer2_get_origin(const struct oonf_layer2_data *l2data) {
+  return l2data->_origin;
 }
 
 /**
- * @param neigh pointer to layer2 network data
- * @param relative relative timestamp when network has been seen last
- *    to store in layer2 network data
+ * Set the value of a layer-2 data object
+ * @param l2data layer-2 data object
+ * @param origin originator of value
+ * @param value new value for data object
  */
-static INLINE void
-oonf_layer2_network_set_last_seen(struct oonf_layer2_network *net, uint64_t relative) {
-  net->_available_data |= OONF_L2NET_LAST_SEEN;
-  net->last_seen = oonf_clock_get_absolute(-relative);
+static inline void
+oonf_layer2_set_value(struct oonf_layer2_data *l2data,
+    uint32_t origin, int64_t value) {
+  l2data->_has_value = true;
+  l2data->_value = value;
+  l2data->_origin = origin;
 }
 
 /**
- * @param neigh pointer to layer2 network data
- * @param frequency frequency of network to store in layer2 network data
+ * Removes the value of a layer-2 data object
+ * @param l2data layer-2 data object
  */
-static INLINE void
-oonf_layer2_network_set_frequency(struct oonf_layer2_network *net, uint64_t frequency) {
-  net->_available_data |= OONF_L2NET_FREQUENCY;
-  net->frequency = frequency;
+static inline void
+oonf_layer2_reset_value(struct oonf_layer2_data *l2data) {
+  l2data->_has_value = false;
+  l2data->_origin = 0;
 }
 
 #endif /* OONF_LAYER2_H_ */
index 7a2db5a..1abd4e8 100644 (file)
@@ -140,10 +140,11 @@ oonf_timer_remove(struct oonf_timer_info *info) {
 /**
  * Start or restart a new timer.
  * @param timer initialized timer entry
- * @param rel_time relative time when the timer should fire
+ * @param first relative time when the timer should fire the first time
+ * @param interval time between two timer events for periodic timers
  */
 void
-oonf_timer_start(struct oonf_timer_entry *timer, uint64_t rel_time)
+oonf_timer_start_ext(struct oonf_timer_entry *timer, uint64_t first, uint64_t interval)
 {
 #ifdef OONF_LOG_DEBUG_INFO
   struct human_readable_str timebuf1;
@@ -169,17 +170,17 @@ oonf_timer_start(struct oonf_timer_entry *timer, uint64_t rel_time)
   }
 
   /* Fill entry */
-  _calc_clock(timer, rel_time);
+  _calc_clock(timer, first);
 
   /* Singleshot or periodical timer ? */
-  timer->_period = timer->info->periodic ? rel_time : 0;
+  timer->_period = timer->info->periodic ? interval : 0;
 
   /* insert into tree */
   avl_insert(&_timer_tree, &timer->_node);
 
   OONF_DEBUG(LOG_TIMER, "TIMER: start timer '%s' firing in %s (%"PRIu64")\n",
       timer->info->name,
-      oonf_clock_toClockString(&timebuf1, rel_time), timer->_clock);
+      oonf_clock_toClockString(&timebuf1, first), timer->_clock);
 
   /* fix 'next event' pointers if necessary */
   if (_scheduling_now) {
@@ -219,18 +220,19 @@ oonf_timer_stop(struct oonf_timer_entry *timer)
  * or an existing timer is started or an existing timer is
  * terminated.
  * @param timer timer_entry pointer
- * @param rel_time time until the new timer should fire, 0 to stop timer
+ * @param first relative time when the timer should fire the first time
+ * @param interval time between two timer events for periodic timers
  */
 void
-oonf_timer_set(struct oonf_timer_entry *timer, uint64_t rel_time)
+oonf_timer_set_ext(struct oonf_timer_entry *timer, uint64_t first, uint64_t interval)
 {
-  if (rel_time == 0) {
+  if (first == 0) {
     /* No good future time provided, kill it. */
     oonf_timer_stop(timer);
   }
   else {
     /* Start or restart the timer */
-    oonf_timer_start(timer, rel_time);
+    oonf_timer_start_ext(timer, first, interval);
   }
 }
 
index 7b55c08..afb1765 100644 (file)
@@ -124,8 +124,8 @@ EXPORT void oonf_timer_walk(void);
 EXPORT void oonf_timer_add(struct oonf_timer_info *ti);
 EXPORT void oonf_timer_remove(struct oonf_timer_info *);
 
-EXPORT void oonf_timer_set(struct oonf_timer_entry *timer, uint64_t rel_time);
-EXPORT void oonf_timer_start(struct oonf_timer_entry *timer, uint64_t rel_time);
+EXPORT void oonf_timer_set_ext(struct oonf_timer_entry *timer, uint64_t first, uint64_t interval);
+EXPORT void oonf_timer_start_ext(struct oonf_timer_entry *timer, uint64_t first, uint64_t interval);
 EXPORT void oonf_timer_stop(struct oonf_timer_entry *);
 
 EXPORT uint64_t oonf_timer_getNextEvent(void);
@@ -157,5 +157,27 @@ oonf_timer_get_due(const struct oonf_timer_entry *timer) {
   return oonf_clock_get_relative(timer->_clock);
 }
 
+/**
+ * This is the one stop shop for all sort of timer manipulation.
+ * Depending on the passed in parameters a new timer is started,
+ * or an existing timer is started or an existing timer is
+ * terminated.
+ * @param timer timer_entry pointer
+ * @param rel_time relative time when the timer should fire
+ */
+static INLINE void
+oonf_timer_set(struct oonf_timer_entry *timer, uint64_t rel_time) {
+  oonf_timer_set_ext(timer, rel_time, rel_time);
+}
+
+/**
+ * Start or restart a new timer.
+ * @param timer initialized timer entry
+ * @param rel_time relative time when the timer should fire
+ */
+static INLINE void
+oonf_timer_start(struct oonf_timer_entry *timer, uint64_t rel_time) {
+  oonf_timer_start_ext(timer, rel_time, rel_time);
+}
 
 #endif /* OONF_TIMER_H_ */
index 53cc9a4..1f81c7c 100644 (file)
@@ -9,4 +9,5 @@ add_subdirectory(remotecontrol)
 # linux specific plugins
 IF (LINUX)
     add_subdirectory(nl80211_listener)
+    add_subdirectory(eth_listener)
 ENDIF (LINUX)
diff --git a/src-plugins/eth_listener/CMakeLists.txt b/src-plugins/eth_listener/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3adaae3
--- /dev/null
@@ -0,0 +1,5 @@
+# set library name
+SET (source "eth_listener.c")
+
+# use generic plugin maker
+oonf_create_plugin("eth_listener" "${source}" "" "")
diff --git a/src-plugins/eth_listener/eth_listener.c b/src-plugins/eth_listener/eth_listener.c
new file mode 100644 (file)
index 0000000..808bb73
--- /dev/null
@@ -0,0 +1,204 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "common/common_types.h"
+#include "config/cfg_schema.h"
+#include "core/oonf_plugins.h"
+#include "subsystems/oonf_clock.h"
+#include "subsystems/oonf_interface.h"
+#include "subsystems/oonf_layer2.h"
+#include "subsystems/oonf_timer.h"
+
+#include "eth_listener/eth_listener.h"
+#include "eth_listener/ethtool-copy.h"
+
+/* definitions */
+struct _eth_config {
+  uint64_t interval;
+};
+
+/* prototypes */
+static int _init(void);
+static void _cleanup(void);
+
+static void _cb_transmission_event(void *);
+static void _cb_config_changed(void);
+
+/* configuration */
+static struct cfg_schema_entry _eth_entries[] = {
+  CFG_MAP_CLOCK_MIN(_eth_config, interval, "interval", "60.0",
+      "Interval between two linklayer information updates", 100),
+};
+
+static struct cfg_schema_section _eth_section = {
+  .type = OONF_PLUGIN_GET_NAME(),
+  .cb_delta_handler = _cb_config_changed,
+  .entries = _eth_entries,
+  .entry_count = ARRAYSIZE(_eth_entries),
+};
+
+static struct _eth_config _config;
+
+/* plugin declaration */
+struct oonf_subsystem eth_listener_subsystem = {
+  .name = OONF_PLUGIN_GET_NAME(),
+  .descr = "OONF ethernet listener plugin",
+  .author = "Henning Rogge",
+
+  .cfg_section = &_eth_section,
+
+  .init = _init,
+  .cleanup = _cleanup,
+};
+DECLARE_OONF_PLUGIN(eth_listener_subsystem);
+
+/* timer for generating netlink requests */
+static struct oonf_timer_info _transmission_timer_info = {
+  .name = "nl80211 listener timer",
+  .callback = _cb_transmission_event,
+  .periodic = true,
+};
+
+static struct oonf_timer_entry _transmission_timer = {
+  .info = &_transmission_timer_info
+};
+
+static int _ioctl_fd;
+static uint32_t _l2_origin;
+
+static int
+_init(void) {
+  _ioctl_fd = socket(AF_INET, SOCK_DGRAM, 0);
+  if (_ioctl_fd == -1) {
+    return -1;
+  }
+
+  oonf_timer_add(&_transmission_timer_info);
+  _l2_origin = oonf_layer2_register_origin();
+
+  return 0;
+}
+
+static void
+_cleanup(void) {
+  oonf_layer2_unregister_origin(_l2_origin);
+
+  oonf_timer_stop(&_transmission_timer);
+  oonf_timer_remove(&_transmission_timer_info);
+
+  close (_ioctl_fd);
+}
+
+static void
+_cb_transmission_event(void *ptr __attribute((unused))) {
+  struct oonf_layer2_net *l2net;
+  struct oonf_interface *interf;
+  struct ethtool_cmd cmd;
+  struct ifreq req;
+  int64_t ethspeed;
+  int err;
+
+  avl_for_each_element(&oonf_interface_tree, interf, _node) {
+    /* layer-2 object for this interface */
+    l2net = oonf_layer2_net_get(&interf->data.mac);
+
+    /* initialize ethtool command */
+    memset(&cmd, 0, sizeof(cmd));
+    cmd.cmd = ETHTOOL_GSET;
+
+    /* initialize interface request */
+    memset(&req, 0, sizeof(req));
+    req.ifr_data = (void *)&cmd;
+    strscpy(req.ifr_name, "eth0", IF_NAMESIZE);
+
+    /* request ethernet information from kernel */
+    err = ioctl(_ioctl_fd, SIOCETHTOOL, &req);
+    if (err != 0) {
+      if (l2net != NULL) {
+        oonf_layer2_net_remove(l2net, _l2_origin);
+      }
+      continue;
+    }
+
+    if (l2net == NULL) {
+      l2net = oonf_layer2_net_add(&interf->data.mac);
+      if (l2net == NULL) {
+        continue;
+      }
+
+      /* copy interface static values */
+      l2net->if_index = interf->data.index;
+      strscpy(l2net->if_name, interf->data.name, sizeof(l2net->if_name));
+      l2net->if_type = OONF_LAYER2_TYPE_ETHERNET;
+    }
+
+    /* get ethernet linkspeed */
+    ethspeed = ethtool_cmd_speed(&cmd);
+    ethspeed *= 1000 * 1000;
+
+    /* set corresponding database entries */
+    oonf_layer2_set_value(&l2net->neighdata[OONF_LAYER2_NEIGH_RX_BITRATE],
+        _l2_origin, ethspeed);
+    oonf_layer2_set_value(&l2net->neighdata[OONF_LAYER2_NEIGH_TX_BITRATE],
+        _l2_origin, ethspeed);
+    oonf_layer2_set_value(&l2net->data[OONF_LAYER2_NET_MAX_BITRATE],
+        _l2_origin, ethspeed);
+  }
+}
+
+static void
+_cb_config_changed(void) {
+  if (cfg_schema_tobin(&_config, _eth_section.post,
+      _eth_entries, ARRAYSIZE(_eth_entries))) {
+    OONF_WARN(LOG_ETH, "Could not convert %s config to bin",
+        OONF_PLUGIN_GET_NAME());
+    return;
+  }
+
+  oonf_timer_set_ext(&_transmission_timer, 1, _config.interval);
+}
diff --git a/src-plugins/eth_listener/eth_listener.h b/src-plugins/eth_listener/eth_listener.h
new file mode 100644 (file)
index 0000000..ee49e0f
--- /dev/null
@@ -0,0 +1,51 @@
+
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef ETH_LISTENER_H_
+#define ETH_LISTENER_H_
+
+#include "common/common_types.h"
+#include "core/oonf_subsystem.h"
+
+#define LOG_ETH eth_listener_subsystem.logging
+EXPORT extern struct oonf_subsystem eth_listener_subsystem;
+
+#endif /* ETH_LISTENER_H_ */
diff --git a/src-plugins/eth_listener/ethtool-copy.h b/src-plugins/eth_listener/ethtool-copy.h
new file mode 100644 (file)
index 0000000..9e26a76
--- /dev/null
@@ -0,0 +1,1036 @@
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ *                                christopher.leech@intel.com,
+ *                                scott.feldman@intel.com)
+ * Portions Copyright (C) Sun Microsystems 2008
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+/* This should work for both 32 and 64 bit userland. */
+struct ethtool_cmd {
+       __u32   cmd;
+       __u32   supported;      /* Features this interface supports */
+       __u32   advertising;    /* Features this interface advertises */
+       __u16   speed;          /* The forced speed (lower bits) in
+                                * Mbps. Please use
+                                * ethtool_cmd_speed()/_set() to
+                                * access it */
+       __u8    duplex;         /* Duplex, half or full */
+       __u8    port;           /* Which connector port */
+       __u8    phy_address;    /* MDIO PHY address (PRTAD for clause 45).
+                                * May be read-only or read-write
+                                * depending on the driver.
+                                */
+       __u8    transceiver;    /* Which transceiver to use */
+       __u8    autoneg;        /* Enable or disable autonegotiation */
+       __u8    mdio_support;   /* MDIO protocols supported.  Read-only.
+                                * Not set by all drivers.
+                                */
+       __u32   maxtxpkt;       /* Tx pkts before generating tx int */
+       __u32   maxrxpkt;       /* Rx pkts before generating rx int */
+       __u16   speed_hi;       /* The forced speed (upper
+                                * bits) in Mbps. Please use
+                                * ethtool_cmd_speed()/_set() to
+                                * access it */
+       __u8    eth_tp_mdix;
+       __u8    reserved2;
+       __u32   lp_advertising; /* Features the link partner advertises */
+       __u32   reserved[2];
+};
+
+static __inline__ void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+                                        __u32 speed)
+{
+
+       ep->speed = (__u16)speed;
+       ep->speed_hi = (__u16)(speed >> 16);
+}
+
+static __inline__ __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep)
+{
+       return (ep->speed_hi << 16) | ep->speed;
+}
+
+/* Device supports clause 22 register access to PHY or peripherals
+ * using the interface defined in <linux/mii.h>.  This should not be
+ * set if there are known to be no such peripherals present or if
+ * the driver only emulates clause 22 registers for compatibility.
+ */
+#define ETH_MDIO_SUPPORTS_C22  1
+
+/* Device supports clause 45 register access to PHY or peripherals
+ * using the interface defined in <linux/mii.h> and <linux/mdio.h>.
+ * This should not be set if there are known to be no such peripherals
+ * present.
+ */
+#define ETH_MDIO_SUPPORTS_C45  2
+
+#define ETHTOOL_FWVERS_LEN     32
+#define ETHTOOL_BUSINFO_LEN    32
+/* these strings are set to whatever the driver author decides... */
+struct ethtool_drvinfo {
+       __u32   cmd;
+       char    driver[32];     /* driver short name, "tulip", "eepro100" */
+       char    version[32];    /* driver version string */
+       char    fw_version[ETHTOOL_FWVERS_LEN]; /* firmware version string */
+       char    bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
+                               /* For PCI devices, use pci_name(pci_dev). */
+       char    reserved1[32];
+       char    reserved2[12];
+                               /*
+                                * Some struct members below are filled in
+                                * using ops->get_sset_count().  Obtaining
+                                * this info from ethtool_drvinfo is now
+                                * deprecated; Use ETHTOOL_GSSET_INFO
+                                * instead.
+                                */
+       __u32   n_priv_flags;   /* number of flags valid in ETHTOOL_GPFLAGS */
+       __u32   n_stats;        /* number of u64's from ETHTOOL_GSTATS */
+       __u32   testinfo_len;
+       __u32   eedump_len;     /* Size of data from ETHTOOL_GEEPROM (bytes) */
+       __u32   regdump_len;    /* Size of data from ETHTOOL_GREGS (bytes) */
+};
+
+#define SOPASS_MAX     6
+/* wake-on-lan settings */
+struct ethtool_wolinfo {
+       __u32   cmd;
+       __u32   supported;
+       __u32   wolopts;
+       __u8    sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+};
+
+/* for passing single values */
+struct ethtool_value {
+       __u32   cmd;
+       __u32   data;
+};
+
+/* for passing big chunks of data */
+struct ethtool_regs {
+       __u32   cmd;
+       __u32   version; /* driver-specific, indicates different chips/revs */
+       __u32   len; /* bytes */
+       __u8    data[0];
+};
+
+/* for passing EEPROM chunks */
+struct ethtool_eeprom {
+       __u32   cmd;
+       __u32   magic;
+       __u32   offset; /* in bytes */
+       __u32   len; /* in bytes */
+       __u8    data[0];
+};
+
+/**
+ * struct ethtool_modinfo - plugin module eeprom information
+ * @cmd: %ETHTOOL_GMODULEINFO
+ * @type: Standard the module information conforms to %ETH_MODULE_SFF_xxxx
+ * @eeprom_len: Length of the eeprom
+ *
+ * This structure is used to return the information to
+ * properly size memory for a subsequent call to %ETHTOOL_GMODULEEEPROM.
+ * The type code indicates the eeprom data format
+ */
+struct ethtool_modinfo {
+       __u32   cmd;
+       __u32   type;
+       __u32   eeprom_len;
+       __u32   reserved[8];
+};
+
+/**
+ * struct ethtool_coalesce - coalescing parameters for IRQs and stats updates
+ * @cmd: ETHTOOL_{G,S}COALESCE
+ * @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
+ *     a packet arrives.
+ * @rx_max_coalesced_frames: Maximum number of packets to receive
+ *     before an RX interrupt.
+ * @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that
+ *     this value applies while an IRQ is being serviced by the host.
+ * @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames,
+ *     except that this value applies while an IRQ is being serviced
+ *     by the host.
+ * @tx_coalesce_usecs: How many usecs to delay a TX interrupt after
+ *     a packet is sent.
+ * @tx_max_coalesced_frames: Maximum number of packets to be sent
+ *     before a TX interrupt.
+ * @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that
+ *     this value applies while an IRQ is being serviced by the host.
+ * @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames,
+ *     except that this value applies while an IRQ is being serviced
+ *     by the host.
+ * @stats_block_coalesce_usecs: How many usecs to delay in-memory
+ *     statistics block updates.  Some drivers do not have an
+ *     in-memory statistic block, and in such cases this value is
+ *     ignored.  This value must not be zero.
+ * @use_adaptive_rx_coalesce: Enable adaptive RX coalescing.
+ * @use_adaptive_tx_coalesce: Enable adaptive TX coalescing.
+ * @pkt_rate_low: Threshold for low packet rate (packets per second).
+ * @rx_coalesce_usecs_low: How many usecs to delay an RX interrupt after
+ *     a packet arrives, when the packet rate is below @pkt_rate_low.
+ * @rx_max_coalesced_frames_low: Maximum number of packets to be received
+ *     before an RX interrupt, when the packet rate is below @pkt_rate_low.
+ * @tx_coalesce_usecs_low: How many usecs to delay a TX interrupt after
+ *     a packet is sent, when the packet rate is below @pkt_rate_low.
+ * @tx_max_coalesced_frames_low: Maximum nuumber of packets to be sent before
+ *     a TX interrupt, when the packet rate is below @pkt_rate_low.
+ * @pkt_rate_high: Threshold for high packet rate (packets per second).
+ * @rx_coalesce_usecs_high: How many usecs to delay an RX interrupt after
+ *     a packet arrives, when the packet rate is above @pkt_rate_high.
+ * @rx_max_coalesced_frames_high: Maximum number of packets to be received
+ *     before an RX interrupt, when the packet rate is above @pkt_rate_high.
+ * @tx_coalesce_usecs_high: How many usecs to delay a TX interrupt after
+ *     a packet is sent, when the packet rate is above @pkt_rate_high.
+ * @tx_max_coalesced_frames_high: Maximum number of packets to be sent before
+ *     a TX interrupt, when the packet rate is above @pkt_rate_high.
+ * @rate_sample_interval: How often to do adaptive coalescing packet rate
+ *     sampling, measured in seconds.  Must not be zero.
+ *
+ * Each pair of (usecs, max_frames) fields specifies this exit
+ * condition for interrupt coalescing:
+ *     (usecs > 0 && time_since_first_completion >= usecs) ||
+ *     (max_frames > 0 && completed_frames >= max_frames)
+ * It is illegal to set both usecs and max_frames to zero as this
+ * would cause interrupts to never be generated.  To disable
+ * coalescing, set usecs = 0 and max_frames = 1.
+ *
+ * Some implementations ignore the value of max_frames and use the
+ * condition:
+ *     time_since_first_completion >= usecs
+ * This is deprecated.  Drivers for hardware that does not support
+ * counting completions should validate that max_frames == !rx_usecs.
+ *
+ * Adaptive RX/TX coalescing is an algorithm implemented by some
+ * drivers to improve latency under low packet rates and improve
+ * throughput under high packet rates.  Some drivers only implement
+ * one of RX or TX adaptive coalescing.  Anything not implemented by
+ * the driver causes these values to be silently ignored.
+ *
+ * When the packet rate is below @pkt_rate_high but above
+ * @pkt_rate_low (both measured in packets per second) the
+ * normal {rx,tx}_* coalescing parameters are used.
+ */
+struct ethtool_coalesce {
+       __u32   cmd;
+       __u32   rx_coalesce_usecs;
+       __u32   rx_max_coalesced_frames;
+       __u32   rx_coalesce_usecs_irq;
+       __u32   rx_max_coalesced_frames_irq;
+       __u32   tx_coalesce_usecs;
+       __u32   tx_max_coalesced_frames;
+       __u32   tx_coalesce_usecs_irq;
+       __u32   tx_max_coalesced_frames_irq;
+       __u32   stats_block_coalesce_usecs;
+       __u32   use_adaptive_rx_coalesce;
+       __u32   use_adaptive_tx_coalesce;
+       __u32   pkt_rate_low;
+       __u32   rx_coalesce_usecs_low;
+       __u32   rx_max_coalesced_frames_low;
+       __u32   tx_coalesce_usecs_low;
+       __u32   tx_max_coalesced_frames_low;
+       __u32   pkt_rate_high;
+       __u32   rx_coalesce_usecs_high;
+       __u32   rx_max_coalesced_frames_high;
+       __u32   tx_coalesce_usecs_high;
+       __u32   tx_max_coalesced_frames_high;
+       __u32   rate_sample_interval;
+};
+
+/* for configuring RX/TX ring parameters */
+struct ethtool_ringparam {
+       __u32   cmd;    /* ETHTOOL_{G,S}RINGPARAM */
+
+       /* Read only attributes.  These indicate the maximum number
+        * of pending RX/TX ring entries the driver will allow the
+        * user to set.
+        */
+       __u32   rx_max_pending;
+       __u32   rx_mini_max_pending;
+       __u32   rx_jumbo_max_pending;
+       __u32   tx_max_pending;
+
+       /* Values changeable by the user.  The valid values are
+        * in the range 1 to the "*_max_pending" counterpart above.
+        */
+       __u32   rx_pending;
+       __u32   rx_mini_pending;
+       __u32   rx_jumbo_pending;
+       __u32   tx_pending;
+};
+
+/**
+ * struct ethtool_channels - configuring number of network channel
+ * @cmd: ETHTOOL_{G,S}CHANNELS
+ * @max_rx: Read only. Maximum number of receive channel the driver support.
+ * @max_tx: Read only. Maximum number of transmit channel the driver support.
+ * @max_other: Read only. Maximum number of other channel the driver support.
+ * @max_combined: Read only. Maximum number of combined channel the driver
+ *     support. Set of queues RX, TX or other.
+ * @rx_count: Valid values are in the range 1 to the max_rx.
+ * @tx_count: Valid values are in the range 1 to the max_tx.
+ * @other_count: Valid values are in the range 1 to the max_other.
+ * @combined_count: Valid values are in the range 1 to the max_combined.
+ *
+ * This can be used to configure RX, TX and other channels.
+ */
+
+struct ethtool_channels {
+       __u32   cmd;
+       __u32   max_rx;
+       __u32   max_tx;
+       __u32   max_other;
+       __u32   max_combined;
+       __u32   rx_count;
+       __u32   tx_count;
+       __u32   other_count;
+       __u32   combined_count;
+};
+
+/* for configuring link flow control parameters */
+struct ethtool_pauseparam {
+       __u32   cmd;    /* ETHTOOL_{G,S}PAUSEPARAM */
+
+       /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+        * being true) the user may set 'autoneg' here non-zero to have the
+        * pause parameters be auto-negotiated too.  In such a case, the
+        * {rx,tx}_pause values below determine what capabilities are
+        * advertised.
+        *
+        * If 'autoneg' is zero or the link is not being auto-negotiated,
+        * then {rx,tx}_pause force the driver to use/not-use pause
+        * flow control.
+        */
+       __u32   autoneg;
+       __u32   rx_pause;
+       __u32   tx_pause;
+};
+
+#define ETH_GSTRING_LEN                32
+enum ethtool_stringset {
+       ETH_SS_TEST             = 0,
+       ETH_SS_STATS,
+       ETH_SS_PRIV_FLAGS,
+       ETH_SS_NTUPLE_FILTERS,  /* Do not use, GRXNTUPLE is now deprecated */
+       ETH_SS_FEATURES,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+       __u32   cmd;            /* ETHTOOL_GSTRINGS */
+       __u32   string_set;     /* string set id e.c. ETH_SS_TEST, etc*/
+       __u32   len;            /* number of strings in the string set */
+       __u8    data[0];
+};
+
+struct ethtool_sset_info {
+       __u32   cmd;            /* ETHTOOL_GSSET_INFO */
+       __u32   reserved;
+       __u64   sset_mask;      /* input: each bit selects an sset to query */
+                               /* output: each bit a returned sset */
+       __u32   data[0];        /* ETH_SS_xxx count, in order, based on bits
+                                  in sset_mask.  One bit implies one
+                                  __u32, two bits implies two
+                                  __u32's, etc. */
+};
+
+/**
+ * enum ethtool_test_flags - flags definition of ethtool_test
+ * @ETH_TEST_FL_OFFLINE: if set perform online and offline tests, otherwise
+ *     only online tests.
+ * @ETH_TEST_FL_FAILED: Driver set this flag if test fails.
+ * @ETH_TEST_FL_EXTERNAL_LB: Application request to perform external loopback
+ *     test.
+ * @ETH_TEST_FL_EXTERNAL_LB_DONE: Driver performed the external loopback test
+ */
+
+enum ethtool_test_flags {
+       ETH_TEST_FL_OFFLINE     = (1 << 0),
+       ETH_TEST_FL_FAILED      = (1 << 1),
+       ETH_TEST_FL_EXTERNAL_LB = (1 << 2),
+       ETH_TEST_FL_EXTERNAL_LB_DONE    = (1 << 3),
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+       __u32   cmd;            /* ETHTOOL_TEST */
+       __u32   flags;          /* ETH_TEST_FL_xxx */
+       __u32   reserved;
+       __u32   len;            /* result length, in number of u64 elements */
+       __u64   data[0];
+};
+
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+       __u32   cmd;            /* ETHTOOL_GSTATS */
+       __u32   n_stats;        /* number of u64's being returned */
+       __u64   data[0];
+};
+
+struct ethtool_perm_addr {
+       __u32   cmd;            /* ETHTOOL_GPERMADDR */
+       __u32   size;
+       __u8    data[0];
+};
+
+/* boolean flags controlling per-interface behavior characteristics.
+ * When reading, the flag indicates whether or not a certain behavior
+ * is enabled/present.  When writing, the flag indicates whether
+ * or not the driver should turn on (set) or off (clear) a behavior.
+ *
+ * Some behaviors may read-only (unconditionally absent or present).
+ * If such is the case, return EINVAL in the set-flags operation if the
+ * flag differs from the read-only value.
+ */
+enum ethtool_flags {
+       ETH_FLAG_TXVLAN         = (1 << 7),     /* TX VLAN offload enabled */
+       ETH_FLAG_RXVLAN         = (1 << 8),     /* RX VLAN offload enabled */
+       ETH_FLAG_LRO            = (1 << 15),    /* LRO is enabled */
+       ETH_FLAG_NTUPLE         = (1 << 27),    /* N-tuple filters enabled */
+       ETH_FLAG_RXHASH         = (1 << 28),
+};
+
+/* The following structures are for supporting RX network flow
+ * classification and RX n-tuple configuration. Note, all multibyte
+ * fields, e.g., ip4src, ip4dst, psrc, pdst, spi, etc. are expected to
+ * be in network byte order.
+ */
+
+/**
+ * struct ethtool_tcpip4_spec - flow specification for TCP/IPv4 etc.
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @psrc: Source port
+ * @pdst: Destination port
+ * @tos: Type-of-service
+ *
+ * This can be used to specify a TCP/IPv4, UDP/IPv4 or SCTP/IPv4 flow.
+ */
+struct ethtool_tcpip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be16  psrc;
+       __be16  pdst;
+       __u8    tos;
+};
+
+/**
+ * struct ethtool_ah_espip4_spec - flow specification for IPsec/IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @spi: Security parameters index
+ * @tos: Type-of-service
+ *
+ * This can be used to specify an IPsec transport or tunnel over IPv4.
+ */
+struct ethtool_ah_espip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be32  spi;
+       __u8    tos;
+};
+
+#define        ETH_RX_NFC_IP4  1
+
+/**
+ * struct ethtool_usrip4_spec - general flow specification for IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @l4_4_bytes: First 4 bytes of transport (layer 4) header
+ * @tos: Type-of-service
+ * @ip_ver: Value must be %ETH_RX_NFC_IP4; mask must be 0
+ * @proto: Transport protocol number; mask must be 0
+ */
+struct ethtool_usrip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be32  l4_4_bytes;
+       __u8    tos;
+       __u8    ip_ver;
+       __u8    proto;
+};
+
+union ethtool_flow_union {
+       struct ethtool_tcpip4_spec              tcp_ip4_spec;
+       struct ethtool_tcpip4_spec              udp_ip4_spec;
+       struct ethtool_tcpip4_spec              sctp_ip4_spec;
+       struct ethtool_ah_espip4_spec           ah_ip4_spec;
+       struct ethtool_ah_espip4_spec           esp_ip4_spec;
+       struct ethtool_usrip4_spec              usr_ip4_spec;
+       struct ethhdr                           ether_spec;
+       __u8                                    hdata[60];
+};
+
+struct ethtool_flow_ext {
+       __be16  vlan_etype;
+       __be16  vlan_tci;
+       __be32  data[2];
+};
+
+/**
+ * struct ethtool_rx_flow_spec - classification rule for RX flows
+ * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
+ * @h_u: Flow fields to match (dependent on @flow_type)
+ * @h_ext: Additional fields to match
+ * @m_u: Masks for flow field bits to be matched
+ * @m_ext: Masks for additional field bits to be matched
+ *     Note, all additional fields must be ignored unless @flow_type
+ *     includes the %FLOW_EXT flag.
+ * @ring_cookie: RX ring/queue index to deliver to, or %RX_CLS_FLOW_DISC
+ *     if packets should be discarded
+ * @location: Location of rule in the table.  Locations must be
+ *     numbered such that a flow matching multiple rules will be
+ *     classified according to the first (lowest numbered) rule.
+ */
+struct ethtool_rx_flow_spec {
+       __u32           flow_type;
+       union ethtool_flow_union h_u;
+       struct ethtool_flow_ext h_ext;
+       union ethtool_flow_union m_u;
+       struct ethtool_flow_ext m_ext;
+       __u64           ring_cookie;
+       __u32           location;
+};
+
+/**
+ * struct ethtool_rxnfc - command to get or set RX flow classification rules
+ * @cmd: Specific command number - %ETHTOOL_GRXFH, %ETHTOOL_SRXFH,
+ *     %ETHTOOL_GRXRINGS, %ETHTOOL_GRXCLSRLCNT, %ETHTOOL_GRXCLSRULE,
+ *     %ETHTOOL_GRXCLSRLALL, %ETHTOOL_SRXCLSRLDEL or %ETHTOOL_SRXCLSRLINS
+ * @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW
+ * @data: Command-dependent value
+ * @fs: Flow classification rule
+ * @rule_cnt: Number of rules to be affected
+ * @rule_locs: Array of used rule locations
+ *
+ * For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating
+ * the fields included in the flow hash, e.g. %RXH_IP_SRC.  The following
+ * structure fields must not be used.
+ *
+ * For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues
+ * on return.
+ *
+ * For %ETHTOOL_GRXCLSRLCNT, @rule_cnt is set to the number of defined
+ * rules on return.  If @data is non-zero on return then it is the
+ * size of the rule table, plus the flag %RX_CLS_LOC_SPECIAL if the
+ * driver supports any special location values.  If that flag is not
+ * set in @data then special location values should not be used.
+ *
+ * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an
+ * existing rule on entry and @fs contains the rule on return.
+ *
+ * For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the
+ * user buffer for @rule_locs on entry.  On return, @data is the size
+ * of the rule table, @rule_cnt is the number of defined rules, and
+ * @rule_locs contains the locations of the defined rules.  Drivers
+ * must use the second parameter to get_rxnfc() instead of @rule_locs.
+ *
+ * For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update.
+ * @fs.@location either specifies the location to use or is a special
+ * location value with %RX_CLS_LOC_SPECIAL flag set.  On return,
+ * @fs.@location is the actual rule location.
+ *
+ * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an
+ * existing rule on entry.
+ *
+ * A driver supporting the special location values for
+ * %ETHTOOL_SRXCLSRLINS may add the rule at any suitable unused
+ * location, and may remove a rule at a later location (lower
+ * priority) that matches exactly the same set of flows.  The special
+ * values are: %RX_CLS_LOC_ANY, selecting any location;
+ * %RX_CLS_LOC_FIRST, selecting the first suitable location (maximum
+ * priority); and %RX_CLS_LOC_LAST, selecting the last suitable
+ * location (minimum priority).  Additional special values may be
+ * defined in future and drivers must return -%EINVAL for any
+ * unrecognised value.
+ */
+struct ethtool_rxnfc {
+       __u32                           cmd;
+       __u32                           flow_type;
+       __u64                           data;
+       struct ethtool_rx_flow_spec     fs;
+       __u32                           rule_cnt;
+       __u32                           rule_locs[0];
+};
+
+
+/**
+ * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
+ * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
+ * @size: On entry, the array size of the user buffer, which may be zero.
+ *     On return from %ETHTOOL_GRXFHINDIR, the array size of the hardware
+ *     indirection table.
+ * @ring_index: RX ring/queue index for each hash value
+ *
+ * For %ETHTOOL_GRXFHINDIR, a @size of zero means that only the size
+ * should be returned.  For %ETHTOOL_SRXFHINDIR, a @size of zero means
+ * the table should be reset to default values.  This last feature
+ * is not supported by the original implementations.
+ */
+struct ethtool_rxfh_indir {
+       __u32   cmd;
+       __u32   size;
+       __u32   ring_index[0];
+};
+
+/**
+ * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter
+ * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
+ * @h_u: Flow field values to match (dependent on @flow_type)
+ * @m_u: Masks for flow field value bits to be ignored
+ * @vlan_tag: VLAN tag to match
+ * @vlan_tag_mask: Mask for VLAN tag bits to be ignored
+ * @data: Driver-dependent data to match
+ * @data_mask: Mask for driver-dependent data bits to be ignored
+ * @action: RX ring/queue index to deliver to (non-negative) or other action
+ *     (negative, e.g. %ETHTOOL_RXNTUPLE_ACTION_DROP)
+ *
+ * For flow types %TCP_V4_FLOW, %UDP_V4_FLOW and %SCTP_V4_FLOW, where
+ * a field value and mask are both zero this is treated as if all mask
+ * bits are set i.e. the field is ignored.
+ */
+struct ethtool_rx_ntuple_flow_spec {
+       __u32            flow_type;
+       union {
+               struct ethtool_tcpip4_spec              tcp_ip4_spec;
+               struct ethtool_tcpip4_spec              udp_ip4_spec;
+               struct ethtool_tcpip4_spec              sctp_ip4_spec;
+               struct ethtool_ah_espip4_spec           ah_ip4_spec;
+               struct ethtool_ah_espip4_spec           esp_ip4_spec;
+               struct ethtool_usrip4_spec              usr_ip4_spec;
+               struct ethhdr                           ether_spec;
+               __u8                                    hdata[72];
+       } h_u, m_u;
+
+       __u16           vlan_tag;
+       __u16           vlan_tag_mask;
+       __u64           data;
+       __u64           data_mask;
+
+       __s32           action;
+#define ETHTOOL_RXNTUPLE_ACTION_DROP   (-1)    /* drop packet */
+#define ETHTOOL_RXNTUPLE_ACTION_CLEAR  (-2)    /* clear filter */
+};
+
+/**
+ * struct ethtool_rx_ntuple - command to set or clear RX flow filter
+ * @cmd: Command number - %ETHTOOL_SRXNTUPLE
+ * @fs: Flow filter specification
+ */
+struct ethtool_rx_ntuple {
+       __u32                                   cmd;
+       struct ethtool_rx_ntuple_flow_spec      fs;
+};
+
+#define ETHTOOL_FLASH_MAX_FILENAME     128
+enum ethtool_flash_op_type {
+       ETHTOOL_FLASH_ALL_REGIONS       = 0,
+};
+
+/* for passing firmware flashing related parameters */
+struct ethtool_flash {
+       __u32   cmd;
+       __u32   region;
+       char    data[ETHTOOL_FLASH_MAX_FILENAME];
+};
+
+/**
+ * struct ethtool_dump - used for retrieving, setting device dump
+ * @cmd: Command number - %ETHTOOL_GET_DUMP_FLAG, %ETHTOOL_GET_DUMP_DATA, or
+ *     %ETHTOOL_SET_DUMP
+ * @version: FW version of the dump, filled in by driver
+ * @flag: driver dependent flag for dump setting, filled in by driver during
+ *       get and filled in by ethtool for set operation
+ * @len: length of dump data, used as the length of the user buffer on entry to
+ *      %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver
+ *      for %ETHTOOL_GET_DUMP_FLAG command
+ * @data: data collected for get dump data operation
+ */
+struct ethtool_dump {
+       __u32   cmd;
+       __u32   version;
+       __u32   flag;
+       __u32   len;
+       __u8    data[0];
+};
+
+/* for returning and changing feature sets */
+
+/**
+ * struct ethtool_get_features_block - block with state of 32 features
+ * @available: mask of changeable features
+ * @requested: mask of features requested to be enabled if possible
+ * @active: mask of currently enabled features
+ * @never_changed: mask of features not changeable for any device
+ */
+struct ethtool_get_features_block {
+       __u32   available;
+       __u32   requested;
+       __u32   active;
+       __u32   never_changed;
+};
+
+/**
+ * struct ethtool_gfeatures - command to get state of device's features
+ * @cmd: command number = %ETHTOOL_GFEATURES
+ * @size: in: number of elements in the features[] array;
+ *       out: number of elements in features[] needed to hold all features
+ * @features: state of features
+ */
+struct ethtool_gfeatures {
+       __u32   cmd;
+       __u32   size;
+       struct ethtool_get_features_block features[0];
+};
+
+/**
+ * struct ethtool_set_features_block - block with request for 32 features
+ * @valid: mask of features to be changed
+ * @requested: values of features to be changed
+ */
+struct ethtool_set_features_block {
+       __u32   valid;
+       __u32   requested;
+};
+
+/**
+ * struct ethtool_sfeatures - command to request change in device's features
+ * @cmd: command number = %ETHTOOL_SFEATURES
+ * @size: array size of the features[] array
+ * @features: feature change masks
+ */
+struct ethtool_sfeatures {
+       __u32   cmd;
+       __u32   size;
+       struct ethtool_set_features_block features[0];
+};
+
+/**
+ * struct ethtool_ts_info - holds a device's timestamping and PHC association
+ * @cmd: command number = %ETHTOOL_GET_TS_INFO
+ * @so_timestamping: bit mask of the sum of the supported SO_TIMESTAMPING flags
+ * @phc_index: device index of the associated PHC, or -1 if there is none
+ * @tx_types: bit mask of the supported hwtstamp_tx_types enumeration values
+ * @rx_filters: bit mask of the supported hwtstamp_rx_filters enumeration values
+ *
+ * The bits in the 'tx_types' and 'rx_filters' fields correspond to
+ * the 'hwtstamp_tx_types' and 'hwtstamp_rx_filters' enumeration values,
+ * respectively.  For example, if the device supports HWTSTAMP_TX_ON,
+ * then (1 << HWTSTAMP_TX_ON) in 'tx_types' will be set.
+ */
+struct ethtool_ts_info {
+       __u32   cmd;
+       __u32   so_timestamping;
+       __s32   phc_index;
+       __u32   tx_types;
+       __u32   tx_reserved[3];
+       __u32   rx_filters;
+       __u32   rx_reserved[3];
+};
+
+/*
+ * %ETHTOOL_SFEATURES changes features present in features[].valid to the
+ * values of corresponding bits in features[].requested. Bits in .requested
+ * not set in .valid or not changeable are ignored.
+ *
+ * Returns %EINVAL when .valid contains undefined or never-changeable bits
+ * or size is not equal to required number of features words (32-bit blocks).
+ * Returns >= 0 if request was completed; bits set in the value mean:
+ *   %ETHTOOL_F_UNSUPPORTED - there were bits set in .valid that are not
+ *     changeable (not present in %ETHTOOL_GFEATURES' features[].available)
+ *     those bits were ignored.
+ *   %ETHTOOL_F_WISH - some or all changes requested were recorded but the
+ *      resulting state of bits masked by .valid is not equal to .requested.
+ *      Probably there are other device-specific constraints on some features
+ *      in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered
+ *      here as though ignored bits were cleared.
+ *   %ETHTOOL_F_COMPAT - some or all changes requested were made by calling
+ *      compatibility functions. Requested offload state cannot be properly
+ *      managed by kernel.
+ *
+ * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of
+ * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands
+ * for ETH_SS_FEATURES string set. First entry in the table corresponds to least
+ * significant bit in features[0] fields. Empty strings mark undefined features.
+ */
+enum ethtool_sfeatures_retval_bits {
+       ETHTOOL_F_UNSUPPORTED__BIT,
+       ETHTOOL_F_WISH__BIT,
+       ETHTOOL_F_COMPAT__BIT,
+};
+
+#define ETHTOOL_F_UNSUPPORTED   (1 << ETHTOOL_F_UNSUPPORTED__BIT)
+#define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT)
+#define ETHTOOL_F_COMPAT        (1 << ETHTOOL_F_COMPAT__BIT)
+
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET           0x00000001 /* Get settings. */
+#define ETHTOOL_SSET           0x00000002 /* Set settings. */
+#define ETHTOOL_GDRVINFO       0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS          0x00000004 /* Get NIC registers. */
+#define ETHTOOL_GWOL           0x00000005 /* Get wake-on-lan options. */
+#define ETHTOOL_SWOL           0x00000006 /* Set wake-on-lan options. */
+#define ETHTOOL_GMSGLVL                0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL                0x00000008 /* Set driver msg level. */
+#define ETHTOOL_NWAY_RST       0x00000009 /* Restart autonegotiation. */
+/* Get link status for host, i.e. whether the interface *and* the
+ * physical port (if there is one) are up (ethtool_value). */
+#define ETHTOOL_GLINK          0x0000000a
+#define ETHTOOL_GEEPROM                0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM                0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GCOALESCE      0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE      0x0000000f /* Set coalesce config. */
+#define ETHTOOL_GRINGPARAM     0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM     0x00000011 /* Set ring parameters. */
+#define ETHTOOL_GPAUSEPARAM    0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM    0x00000013 /* Set pause parameters. */
+#define ETHTOOL_GRXCSUM                0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM                0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM                0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM                0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG            0x00000018 /* Get scatter-gather enable
+                                           * (ethtool_value) */
+#define ETHTOOL_SSG            0x00000019 /* Set scatter-gather enable
+                                           * (ethtool_value). */
+#define ETHTOOL_TEST           0x0000001a /* execute NIC self-test. */
+#define ETHTOOL_GSTRINGS       0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID                0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS         0x0000001d /* get NIC-specific statistics */
+#define ETHTOOL_GTSO           0x0000001e /* Get TSO enable (ethtool_value) */
+#define ETHTOOL_STSO           0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_GPERMADDR      0x00000020 /* Get permanent hardware address */
+#define ETHTOOL_GUFO           0x00000021 /* Get UFO enable (ethtool_value) */
+#define ETHTOOL_SUFO           0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_GGSO           0x00000023 /* Get GSO enable (ethtool_value) */
+#define ETHTOOL_SGSO           0x00000024 /* Set GSO enable (ethtool_value) */
+#define ETHTOOL_GFLAGS         0x00000025 /* Get flags bitmap(ethtool_value) */
+#define ETHTOOL_SFLAGS         0x00000026 /* Set flags bitmap(ethtool_value) */
+#define ETHTOOL_GPFLAGS                0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS                0x00000028 /* Set driver-private flags bitmap */
+
+#define ETHTOOL_GRXFH          0x00000029 /* Get RX flow hash configuration */
+#define ETHTOOL_SRXFH          0x0000002a /* Set RX flow hash configuration */
+#define ETHTOOL_GGRO           0x0000002b /* Get GRO enable (ethtool_value) */
+#define ETHTOOL_SGRO           0x0000002c /* Set GRO enable (ethtool_value) */
+#define ETHTOOL_GRXRINGS       0x0000002d /* Get RX rings available for LB */
+#define ETHTOOL_GRXCLSRLCNT    0x0000002e /* Get RX class rule count */
+#define ETHTOOL_GRXCLSRULE     0x0000002f /* Get RX classification rule */
+#define ETHTOOL_GRXCLSRLALL    0x00000030 /* Get all RX classification rule */
+#define ETHTOOL_SRXCLSRLDEL    0x00000031 /* Delete RX classification rule */
+#define ETHTOOL_SRXCLSRLINS    0x00000032 /* Insert RX classification rule */
+#define ETHTOOL_FLASHDEV       0x00000033 /* Flash firmware to device */
+#define ETHTOOL_RESET          0x00000034 /* Reset hardware */
+#define ETHTOOL_SRXNTUPLE      0x00000035 /* Add an n-tuple filter to device */
+#define ETHTOOL_GRXNTUPLE      0x00000036 /* deprecated */
+#define ETHTOOL_GSSET_INFO     0x00000037 /* Get string set info */
+#define ETHTOOL_GRXFHINDIR     0x00000038 /* Get RX flow hash indir'n table */
+#define ETHTOOL_SRXFHINDIR     0x00000039 /* Set RX flow hash indir'n table */
+
+#define ETHTOOL_GFEATURES      0x0000003a /* Get device offload settings */
+#define ETHTOOL_SFEATURES      0x0000003b /* Change device offload settings */
+#define ETHTOOL_GCHANNELS      0x0000003c /* Get no of channels */
+#define ETHTOOL_SCHANNELS      0x0000003d /* Set no of channels */
+#define ETHTOOL_SET_DUMP       0x0000003e /* Set dump settings */
+#define ETHTOOL_GET_DUMP_FLAG  0x0000003f /* Get dump settings */
+#define ETHTOOL_GET_DUMP_DATA  0x00000040 /* Get dump data */
+#define ETHTOOL_GET_TS_INFO    0x00000041 /* Get time stamping and PHC info */
+#define ETHTOOL_GMODULEINFO    0x00000042 /* Get plug-in module information */
+#define ETHTOOL_GMODULEEEPROM  0x00000043 /* Get plug-in module eeprom */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET         ETHTOOL_GSET
+#define SPARC_ETH_SSET         ETHTOOL_SSET
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half         (1 << 0)
+#define SUPPORTED_10baseT_Full         (1 << 1)
+#define SUPPORTED_100baseT_Half                (1 << 2)
+#define SUPPORTED_100baseT_Full                (1 << 3)
+#define SUPPORTED_1000baseT_Half       (1 << 4)
+#define SUPPORTED_1000baseT_Full       (1 << 5)
+#define SUPPORTED_Autoneg              (1 << 6)
+#define SUPPORTED_TP                   (1 << 7)
+#define SUPPORTED_AUI                  (1 << 8)
+#define SUPPORTED_MII                  (1 << 9)
+#define SUPPORTED_FIBRE                        (1 << 10)
+#define SUPPORTED_BNC                  (1 << 11)
+#define SUPPORTED_10000baseT_Full      (1 << 12)
+#define SUPPORTED_Pause                        (1 << 13)
+#define SUPPORTED_Asym_Pause           (1 << 14)
+#define SUPPORTED_2500baseX_Full       (1 << 15)
+#define SUPPORTED_Backplane            (1 << 16)
+#define SUPPORTED_1000baseKX_Full      (1 << 17)
+#define SUPPORTED_10000baseKX4_Full    (1 << 18)
+#define SUPPORTED_10000baseKR_Full     (1 << 19)
+#define SUPPORTED_10000baseR_FEC       (1 << 20)
+#define SUPPORTED_20000baseMLD2_Full   (1 << 21)
+#define SUPPORTED_20000baseKR2_Full    (1 << 22)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half                (1 << 0)
+#define ADVERTISED_10baseT_Full                (1 << 1)
+#define ADVERTISED_100baseT_Half       (1 << 2)
+#define ADVERTISED_100baseT_Full       (1 << 3)
+#define ADVERTISED_1000baseT_Half      (1 << 4)
+#define ADVERTISED_1000baseT_Full      (1 << 5)
+#define ADVERTISED_Autoneg             (1 << 6)
+#define ADVERTISED_TP                  (1 << 7)
+#define ADVERTISED_AUI                 (1 << 8)
+#define ADVERTISED_MII                 (1 << 9)
+#define ADVERTISED_FIBRE               (1 << 10)
+#define ADVERTISED_BNC                 (1 << 11)
+#define ADVERTISED_10000baseT_Full     (1 << 12)
+#define ADVERTISED_Pause               (1 << 13)
+#define ADVERTISED_Asym_Pause          (1 << 14)
+#define ADVERTISED_2500baseX_Full      (1 << 15)
+#define ADVERTISED_Backplane           (1 << 16)
+#define ADVERTISED_1000baseKX_Full     (1 << 17)
+#define ADVERTISED_10000baseKX4_Full   (1 << 18)
+#define ADVERTISED_10000baseKR_Full    (1 << 19)
+#define ADVERTISED_10000baseR_FEC      (1 << 20)
+#define ADVERTISED_20000baseMLD2_Full  (1 << 21)
+#define ADVERTISED_20000baseKR2_Full   (1 << 22)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was forced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10               10
+#define SPEED_100              100
+#define SPEED_1000             1000
+#define SPEED_2500             2500
+#define SPEED_10000            10000
+#define SPEED_UNKNOWN          -1
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF            0x00
+#define DUPLEX_FULL            0x01
+#define DUPLEX_UNKNOWN         0xff
+
+/* Which connector port. */
+#define PORT_TP                        0x00
+#define PORT_AUI               0x01
+#define PORT_MII               0x02
+#define PORT_FIBRE             0x03
+#define PORT_BNC               0x04
+#define PORT_DA                        0x05
+#define PORT_NONE              0xef
+#define PORT_OTHER             0xff
+
+/* Which transceiver to use. */
+#define XCVR_INTERNAL          0x00
+#define XCVR_EXTERNAL          0x01
+#define XCVR_DUMMY1            0x02
+#define XCVR_DUMMY2            0x03
+#define XCVR_DUMMY3            0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE                0x00
+#define AUTONEG_ENABLE         0x01
+
+/* Mode MDI or MDI-X */
+#define ETH_TP_MDI_INVALID     0x00
+#define ETH_TP_MDI             0x01
+#define ETH_TP_MDI_X           0x02
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY               (1 << 0)
+#define WAKE_UCAST             (1 << 1)
+#define WAKE_MCAST             (1 << 2)
+#define WAKE_BCAST             (1 << 3)
+#define WAKE_ARP               (1 << 4)
+#define WAKE_MAGIC             (1 << 5)
+#define WAKE_MAGICSECURE       (1 << 6) /* only meaningful if WAKE_MAGIC */
+
+/* L2-L4 network traffic flow types */
+#define        TCP_V4_FLOW     0x01    /* hash or spec (tcp_ip4_spec) */
+#define        UDP_V4_FLOW     0x02    /* hash or spec (udp_ip4_spec) */
+#define        SCTP_V4_FLOW    0x03    /* hash or spec (sctp_ip4_spec) */
+#define        AH_ESP_V4_FLOW  0x04    /* hash only */
+#define        TCP_V6_FLOW     0x05    /* hash only */
+#define        UDP_V6_FLOW     0x06    /* hash only */
+#define        SCTP_V6_FLOW    0x07    /* hash only */
+#define        AH_ESP_V6_FLOW  0x08    /* hash only */
+#define        AH_V4_FLOW      0x09    /* hash or spec (ah_ip4_spec) */
+#define        ESP_V4_FLOW     0x0a    /* hash or spec (esp_ip4_spec) */
+#define        AH_V6_FLOW      0x0b    /* hash only */
+#define        ESP_V6_FLOW     0x0c    /* hash only */
+#define        IP_USER_FLOW    0x0d    /* spec only (usr_ip4_spec) */
+#define        IPV4_FLOW       0x10    /* hash only */
+#define        IPV6_FLOW       0x11    /* hash only */
+#define        ETHER_FLOW      0x12    /* spec only (ether_spec) */
+/* Flag to enable additional fields in struct ethtool_rx_flow_spec */
+#define        FLOW_EXT        0x80000000
+
+/* L3-L4 network traffic flow hash options */
+#define        RXH_L2DA        (1 << 1)
+#define        RXH_VLAN        (1 << 2)
+#define        RXH_L3_PROTO    (1 << 3)
+#define        RXH_IP_SRC      (1 << 4)
+#define        RXH_IP_DST      (1 << 5)
+#define        RXH_L4_B_0_1    (1 << 6) /* src port in case of TCP/UDP/SCTP */
+#define        RXH_L4_B_2_3    (1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define        RXH_DISCARD     (1 << 31)
+
+#define        RX_CLS_FLOW_DISC        0xffffffffffffffffULL
+
+/* Special RX classification rule insert location values */
+#define RX_CLS_LOC_SPECIAL     0x80000000      /* flag */
+#define RX_CLS_LOC_ANY         0xffffffff
+#define RX_CLS_LOC_FIRST       0xfffffffe
+#define RX_CLS_LOC_LAST                0xfffffffd
+
+/* EEPROM Standards for plug in modules */
+#define ETH_MODULE_SFF_8079            0x1
+#define ETH_MODULE_SFF_8079_LEN                256
+#define ETH_MODULE_SFF_8472            0x2
+#define ETH_MODULE_SFF_8472_LEN                512
+
+/* Reset flags */
+/* The reset() operation must clear the flags for the components which
+ * were actually reset.  On successful return, the flags indicate the
+ * components which were not reset, either because they do not exist
+ * in the hardware or because they cannot be reset independently.  The
+ * driver must never reset any components that were not requested.
+ */
+enum ethtool_reset_flags {
+       /* These flags represent components dedicated to the interface
+        * the command is addressed to.  Shift any flag left by
+        * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+        * same type.
+        */
+       ETH_RESET_MGMT          = 1 << 0,       /* Management processor */
+       ETH_RESET_IRQ           = 1 << 1,       /* Interrupt requester */
+       ETH_RESET_DMA           = 1 << 2,       /* DMA engine */
+       ETH_RESET_FILTER        = 1 << 3,       /* Filtering/flow direction */
+       ETH_RESET_OFFLOAD       = 1 << 4,       /* Protocol offload */
+       ETH_RESET_MAC           = 1 << 5,       /* Media access controller */
+       ETH_RESET_PHY           = 1 << 6,       /* Transceiver/PHY */
+       ETH_RESET_RAM           = 1 << 7,       /* RAM shared between
+                                                * multiple components */
+
+       ETH_RESET_DEDICATED     = 0x0000ffff,   /* All components dedicated to
+                                                * this interface */
+       ETH_RESET_ALL           = 0xffffffff,   /* All components used by this
+                                                * interface, even if shared */
+};
+#define ETH_RESET_SHARED_SHIFT 16
+
+#endif /* _LINUX_ETHTOOL_H */
index 80c7928..f14bbea 100644 (file)
 #define KEY_neighbor "neighbor"
 #define KEY_radio "radio"
 #define KEY_ifindex "ifindex"
+#define KEY_ifid    "ifid"
 #define KEY_interface "interface"
-#define KEY_active "active"
-#define KEY_shortactive "shortactive"
 #define KEY_lastseen "lastseen"
-#define KEY_ssid "ssid"
-#define KEY_frequency "frequency"
-#define KEY_signal "signal"
-#define KEY_rxbitrate "rxbitrate"
-#define KEY_rxbytes "rxbytes"
-#define KEY_rxpackets "rxpackets"
-#define KEY_txbitrate "txbitrate"
-#define KEY_txbytes "txbytes"
-#define KEY_txpackets "txpackets"
-#define KEY_txretries "txretries"
-#define KEY_txfailed "txfailed"
 
 /* definitions */
 struct _l2viewer_config {
@@ -135,123 +123,83 @@ static struct oonf_telnet_command _telnet_cmd =
 
 /* template buffers */
 static struct {
-  struct netaddr_str neighbor;
-  struct netaddr_str radio;
+  struct netaddr_str neigh_addr;
+  struct netaddr_str radio_addr;
   char ifindex[10];
   char interface[IF_NAMESIZE];
-  char active[JSON_BOOL_LENGTH];
-  char shortactive[2];
   struct human_readable_str lastseen;
-  char ssid[33];
-  struct human_readable_str frequency;
-  char signal[7];
-  struct human_readable_str rxbitrate;
-  struct human_readable_str rxbytes;
-  struct human_readable_str rxpackets;
-  struct human_readable_str txbitrate;
-  struct human_readable_str txbytes;
-  struct human_readable_str txpackets;
-  struct human_readable_str txretries;
-  struct human_readable_str txfailed;
+  char if_id[33];
+  struct human_readable_str network[OONF_LAYER2_NET_COUNT];
+  struct human_readable_str neighbor[OONF_LAYER2_NEIGH_COUNT];
 } _template_buf;
 
-static struct abuf_template_data _template_neigh_data[] = {
-  { .key = KEY_neighbor, .value = _template_buf.neighbor.buf, .string = true},
-  { .key = KEY_radio, .value = _template_buf.radio.buf, .string = true},
+static struct abuf_template_data _template_neigh_data[5 + OONF_LAYER2_NEIGH_COUNT] = {
+  { .key = KEY_neighbor, .value = _template_buf.neigh_addr.buf, .string = true},
+  { .key = KEY_radio, .value = _template_buf.radio_addr.buf, .string = true},
   { .key = KEY_ifindex, .value = _template_buf.ifindex },
   { .key = KEY_interface, .value = _template_buf.interface, .string = true },
-  { .key = KEY_active, .value = _template_buf.active },
-  { .key = KEY_shortactive, .value = _template_buf.shortactive, .string = true },
   { .key = KEY_lastseen, .value = _template_buf.lastseen.buf },
-  { .key = KEY_signal, .value = _template_buf.signal },
-  { .key = KEY_rxbitrate, .value = _template_buf.rxbitrate.buf },
-  { .key = KEY_rxbytes, .value = _template_buf.rxbytes.buf },
-  { .key = KEY_rxpackets, .value = _template_buf.rxpackets.buf },
-  { .key = KEY_txbitrate, .value = _template_buf.txbitrate.buf },
-  { .key = KEY_txbytes, .value = _template_buf.txbytes.buf },
-  { .key = KEY_txpackets, .value = _template_buf.txpackets.buf },
-  { .key = KEY_txretries, .value = _template_buf.txretries.buf },
-  { .key = KEY_txfailed, .value = _template_buf.txfailed.buf },
 };
 
-static struct abuf_template_data _template_net_data[] = {
-  { .key = KEY_radio, .value = _template_buf.radio.buf, .string = true},
+static struct abuf_template_data _template_net_data[5 + OONF_LAYER2_NET_COUNT] = {
+  { .key = KEY_radio, .value = _template_buf.radio_addr.buf, .string = true},
   { .key = KEY_ifindex, .value = _template_buf.ifindex },
   { .key = KEY_interface, .value = _template_buf.interface, .string = true },
-  { .key = KEY_active, .value = _template_buf.active },
   { .key = KEY_lastseen, .value = _template_buf.lastseen.buf },
-  { .key = KEY_ssid, .value = _template_buf.ssid, .string = true},
-  { .key = KEY_frequency, .value = _template_buf.frequency.buf },
+  { .key = KEY_ifid, .value = _template_buf.if_id, .string = true},
 };
 
 struct _command_params {
-  const char *cmd_full;
-  const char *cmd_active;
-  const char *cmd_inactive;
+  const char *sub;
   const char *tmpl_full;
   const char *tmpl_table;
-  const char *tmpl_filtered_table;
   const char *headline_table;
-  const char *headline_filtered_table;
 
   /* set by runtime */
   const char *template;
-  bool active;
-  bool inactive;
 };
 
 struct _command_params _net_params = {
-  .cmd_full = "net_full",
-  .cmd_active = "net",
-  .cmd_inactive = "net_inactive",
+  .sub = "net",
 
   .tmpl_full =
-      "Radio MAC: %" KEY_radio     "%\n"
-      "Active:    %" KEY_active    "%\n"
-      "If-Index:  %" KEY_ifindex   "%\n"
-      "Interface: %" KEY_interface "%\n"
-      "SSID:      %" KEY_ssid      "%\n"
-      "Last seen: %" KEY_lastseen  "% seconds ago\n"
-      "Frequency: %" KEY_frequency "%\n"
+      "Radio MAC:    %" KEY_radio     "%\n"
+      "If-Index:     %" KEY_ifindex   "%\n"
+      "Interface:    %" KEY_interface "%\n"
+      "Interf. ID:   %" KEY_ifid      "%\n"
+      "Last seen:    %" KEY_lastseen  "% seconds ago\n"
+      "Frequency:    %" OONF_LAYER2_NET_FREQUENCY_KEY "%\n"
+      "Max. Bitrate: %" OONF_LAYER2_NET_MAX_BITRATE_KEY "%\n"
       "\n",
   .tmpl_table =
-      "%"KEY_shortactive"%%"KEY_interface"%\t%"KEY_radio"%\n",
-  .tmpl_filtered_table =
       "%"KEY_interface"%\t%"KEY_radio"%\n",
 
-  .headline_table = "  If\tRadio            \n",
-  .headline_filtered_table = "If\tRadio            \n",
+  .headline_table = "If\tRadio\n",
 };
 
 struct _command_params _neigh_params = {
-  .cmd_full = "neigh_full",
-  .cmd_active = "neigh",
-  .cmd_inactive = "neigh_inactive",
+  .sub = "neigh",
 
   .tmpl_full =
       "Neighbor MAC: %" KEY_neighbor  "%\n"
-      "Active:       %" KEY_active    "%\n"
       "Radio MAC:    %" KEY_radio     "%\n"
       "If-Index:     %" KEY_ifindex   "%\n"
       "Interface:    %" KEY_interface "%\n"
       "Last seen:    %" KEY_lastseen  "% seconds ago\n"
-      "Signal:       %" KEY_signal    "% dBm\n"
-      "Rx bitrate:   %" KEY_rxbitrate "%\n"
-      "Rx bytes:     %" KEY_rxbytes   "%\n"
-      "Rx packets:   %" KEY_rxpackets "%\n"
-      "Tx bitrate:   %" KEY_txbitrate "%\n"
-      "Tx bytes:     %" KEY_txbytes   "%\n"
-      "Tx packets:   %" KEY_txpackets "%\n"
-      "Tx retries:   %" KEY_txretries "%\n"
-      "Tx failed:    %" KEY_txfailed  "%\n"
+      "Signal:       %" OONF_LAYER2_NEIGH_SIGNAL_KEY    "% dBm\n"
+      "Rx bitrate:   %" OONF_LAYER2_NEIGH_RX_BITRATE_KEY "%\n"
+      "Rx bytes:     %" OONF_LAYER2_NEIGH_RX_BYTES_KEY   "%\n"
+      "Rx frames:    %" OONF_LAYER2_NEIGH_RX_FRAMES_KEY "%\n"
+      "Tx bitrate:   %" OONF_LAYER2_NEIGH_TX_BITRATE_KEY "%\n"
+      "Tx bytes:     %" OONF_LAYER2_NEIGH_TX_BYTES_KEY   "%\n"
+      "Tx frames:    %" OONF_LAYER2_NEIGH_TX_FRAMES_KEY "%\n"
+      "Tx retries:   %" OONF_LAYER2_NEIGH_TX_RETRIES_KEY "%\n"
+      "Tx failed:    %" OONF_LAYER2_NEIGH_TX_FAILED_KEY  "%\n"
       "\n",
   .tmpl_table =
-      "%"KEY_shortactive"%%"KEY_interface"%\t%"KEY_radio"%\t%"KEY_neighbor"%\n",
-  .tmpl_filtered_table =
       "%"KEY_interface"%\t%"KEY_radio"%\t%"KEY_neighbor"%\n",
 
-  .headline_table = "  If\tRadio            \tNeighbor\n",
-  .headline_filtered_table = "If\tRadio            \tNeighbor\n",
+  .headline_table = "  If\tRadio\tNeighbor\n",
 };
 
 /**
@@ -260,7 +208,21 @@ struct _command_params _neigh_params = {
  */
 static int
 _init(void) {
+  int i;
+
   oonf_telnet_add(&_telnet_cmd);
+
+  /* initialize templates */
+  for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
+    _template_net_data[5+i].key = oonf_layer2_metadata_net[i].key;
+    _template_net_data[5+i].string = false;
+    _template_net_data[5+i].value = _template_buf.network[i].buf;
+  }
+  for (i=0; i<OONF_LAYER2_NEIGH_COUNT; i++) {
+    _template_neigh_data[5+i].key = oonf_layer2_metadata_neigh[i].key;
+    _template_neigh_data[5+i].string = false;
+    _template_neigh_data[5+i].value = _template_buf.neighbor[i].buf;
+  }
   return 0;
 }
 
@@ -272,32 +234,44 @@ _cleanup(void) {
   oonf_telnet_remove(&_telnet_cmd);
 }
 
+static int
+_print_value(struct human_readable_str *dst, struct oonf_layer2_data *data,
+    const struct oonf_layer2_metadata *meta, bool raw) {
+  int64_t value;
+
+  value = oonf_layer2_get_value(data);
+  if (str_get_human_readable_s64(dst, value,
+      meta->unit, meta->fraction, meta->binary, raw)) {
+    return 0;
+  }
+  return -1;
+}
+
 /**
- * Print the data of a layer2 network to the telnet stream
+ * Print the data of a layer2 addr to the telnet stream
  * @param out pointer to output stream
- * @param net pointer to layer2 network data
+ * @param net pointer to layer2 addr data
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-_init_network_template(struct oonf_layer2_network *net, bool raw) {
+_init_network_template_value(struct oonf_layer2_net *net, bool raw) {
+  int i;
+
   memset (&_template_buf, 0, sizeof(_template_buf));
 
-  if (NULL == netaddr_to_string(&_template_buf.radio, &net->radio_id))
+  if (NULL == netaddr_to_string(&_template_buf.radio_addr, &net->addr))
     return -1;
 
-  strcpy (_template_buf.active, abuf_json_getbool(net->active));
-  strcpy (_template_buf.shortactive, net->active ? "*" : " ");
-
   if (net->if_index) {
     sprintf(_template_buf.ifindex, "%u", net->if_index);
     if_indextoname(net->if_index, _template_buf.interface);
   }
 
-  if (oonf_layer2_network_has_ssid(net)) {
-    strscpy(_template_buf.ssid, net->ssid, sizeof(_template_buf.ssid));
+  if (net->if_ident[0]) {
+    strscpy(_template_buf.if_id, net->if_ident, sizeof(_template_buf.if_id));
   }
 
-  if (oonf_layer2_network_has_last_seen(net)) {
+  if (net->last_seen) {
     int64_t relative;
 
     relative = oonf_clock_get_relative(net->last_seen);
@@ -305,10 +279,14 @@ _init_network_template(struct oonf_layer2_network *net, bool raw) {
       return -1;
     }
   }
-  if (oonf_layer2_network_has_frequency(net)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.frequency, net->frequency, "Hz", 3, false, raw)) {
-      return -1;
+
+
+  for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
+    if (oonf_layer2_has_value(&net->data[i])) {
+      if (_print_value(&_template_buf.network[i], &net->data[i],
+          &oonf_layer2_metadata_net[i],raw)) {
+        return -1;
+      }
     }
   }
   return 0;
@@ -321,22 +299,21 @@ _init_network_template(struct oonf_layer2_network *net, bool raw) {
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-_init_neighbor_template(struct oonf_layer2_neighbor *neigh, bool raw) {
-  if (NULL == netaddr_to_string(&_template_buf.neighbor, &neigh->key.neighbor_mac))
-    return -1;
+_init_neighbor_template_value(struct oonf_layer2_neigh *neigh, bool raw) {
+  int i;
 
-  strcpy (_template_buf.active, abuf_json_getbool(neigh->active));
-  strcpy (_template_buf.shortactive, neigh->active ? "*" : " ");
+  if (NULL == netaddr_to_string(&_template_buf.neigh_addr, &neigh->addr))
+    return -1;
 
-  if (NULL == netaddr_to_string(&_template_buf.radio, &neigh->key.radio_mac))
+  if (NULL == netaddr_to_string(&_template_buf.radio_addr, &neigh->network->addr))
     return -1;
 
-  if (neigh->if_index) {
-    sprintf(_template_buf.ifindex, "%u", neigh->if_index);
-    if_indextoname(neigh->if_index, _template_buf.interface);
+  if (neigh->network->if_index) {
+    sprintf(_template_buf.ifindex, "%u", neigh->network->if_index);
+    if_indextoname(neigh->network->if_index, _template_buf.interface);
   }
 
-  if (oonf_layer2_neighbor_has_last_seen(neigh)) {
+  if (neigh->last_seen) {
     int64_t relative;
 
     relative = oonf_clock_get_relative(neigh->last_seen);
@@ -345,55 +322,12 @@ _init_neighbor_template(struct oonf_layer2_neighbor *neigh, bool raw) {
     }
   }
 
-  if (oonf_layer2_neighbor_has_signal(neigh)) {
-    sprintf(_template_buf.signal, "%d", neigh->signal_dbm);
-  }
-  if (oonf_layer2_neighbor_has_rx_bitrate(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.rxbitrate, neigh->rx_bitrate, "bit/s", 1, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_rx_bytes(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.rxbytes, neigh->rx_bytes, "Byte", 1, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_rx_packets(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.rxpackets, neigh->rx_packets, "", 0, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_tx_bitrate(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.txbitrate, neigh->tx_bitrate, "bit/s", 1, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_tx_bytes(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.txbytes, neigh->tx_bytes, "Byte", 1, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_tx_packets(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.txpackets, neigh->tx_packets, "", 0, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_tx_retries(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.txretries, neigh->tx_retries, "", 3, true, raw)) {
-      return -1;
-    }
-  }
-  if (oonf_layer2_neighbor_has_tx_failed(neigh)) {
-    if (NULL == str_get_human_readable_u64(
-        &_template_buf.txfailed, neigh->tx_failed, "", 3, true, raw)) {
-      return -1;
+  for (i=0; i<OONF_LAYER2_NEIGH_COUNT; i++) {
+    if (oonf_layer2_has_value(&neigh->data[i])) {
+      if (_print_value(&_template_buf.neighbor[i], &neigh->data[i],
+          &oonf_layer2_metadata_neigh[i], raw)) {
+        return -1;
+      }
     }
   }
   return 0;
@@ -410,34 +344,14 @@ _init_neighbor_template(struct oonf_layer2_neighbor *neigh, bool raw) {
 static bool
 _parse_mode(struct autobuf *out, const char *cmd, struct _command_params *params) {
   const char *next;
-  bool filtered;
 
-  filtered = false;
-  if ((next = str_hasnextword(cmd, params->cmd_full))) {
-    params->active = true;
-    params->inactive = true;
-  }
-  else if ((next = str_hasnextword(cmd, params->cmd_active))) {
-    params->active = true;
-    filtered = true;
-  }
-  else if ((next = str_hasnextword(cmd, params->cmd_inactive))) {
-    params->inactive = true;
-    filtered = true;
-  }
-  else {
+  if ((next = str_hasnextword(cmd, params->sub)) == NULL) {
     return false;
   }
 
   if (strcasecmp(next, "list") == 0) {
-    if (filtered) {
-      abuf_puts(out, params->headline_filtered_table);
-      params->template = params->tmpl_filtered_table;
-    }
-    else {
-      abuf_puts(out, params->headline_table);
-      params->template = params->tmpl_table;
-    }
+    abuf_puts(out, params->headline_table);
+    params->template = params->tmpl_table;
   }
   else if (strcasecmp(next, JSON_TEMPLATE_FORMAT) == 0) {
     params->template = NULL;
@@ -458,8 +372,8 @@ _parse_mode(struct autobuf *out, const char *cmd, struct _command_params *params
  */
 static enum oonf_telnet_result
 _cb_handle_layer2(struct oonf_telnet_data *data) {
-  struct oonf_layer2_network *net;
-  struct oonf_layer2_neighbor *neigh;
+  struct oonf_layer2_net *net;
+  struct oonf_layer2_neigh *neigh;
   struct abuf_template_storage *tmpl_storage = NULL;
 
   if (data->parameter == NULL || *data->parameter == 0) {
@@ -476,19 +390,17 @@ _cb_handle_layer2(struct oonf_telnet_data *data) {
       }
     }
 
-    avl_for_each_element(&oonf_layer2_network_id_tree, net, _id_node) {
-      if (net->active ? _net_params.active : _net_params.inactive) {
-        if (_init_network_template(net, _net_params.template == NULL)) {
-          free(tmpl_storage);
-          return TELNET_RESULT_INTERNAL_ERROR;
-        }
-        if (_net_params.template) {
-          abuf_add_template(data->out, _net_params.template, tmpl_storage);
-        }
-        else {
-          abuf_add_json(data->out, "",
-              _template_net_data, ARRAYSIZE(_template_net_data));
-        }
+    avl_for_each_element(&oonf_layer2_net_tree, net, _node) {
+      if (_init_network_template_value(net, _net_params.template == NULL)) {
+        free(tmpl_storage);
+        return TELNET_RESULT_INTERNAL_ERROR;
+      }
+      if (_net_params.template) {
+        abuf_add_template(data->out, _net_params.template, tmpl_storage);
+      }
+      else {
+        abuf_add_json(data->out, "",
+            _template_net_data, ARRAYSIZE(_template_net_data));
       }
     }
   }
@@ -501,9 +413,9 @@ _cb_handle_layer2(struct oonf_telnet_data *data) {
       }
     }
 
-    avl_for_each_element(&oonf_layer2_neighbor_tree, neigh, _node) {
-      if (neigh->active ? _neigh_params.active : _neigh_params.inactive) {
-        if (_init_neighbor_template(neigh, _neigh_params.template == NULL)) {
+    avl_for_each_element(&oonf_layer2_net_tree, net, _node) {
+      avl_for_each_element(&net->neighbors, neigh, _node) {
+        if (_init_neighbor_template_value(neigh, _neigh_params.template == NULL)) {
           free(tmpl_storage);
           return TELNET_RESULT_INTERNAL_ERROR;
         }
index 4c91d12..e3b5b71 100644 (file)
@@ -146,7 +146,9 @@ static bool _nl80211_mc_set = false;
 static char _last_queried_if[IF_NAMESIZE];
 static enum query_type _next_query_type;
 
-/* timer for generating netlink requests */
+static uint32_t _l2_origin;
+
+/* timer for generatstatic ing netlink requests */
 static struct oonf_timer_info _transmission_timer_info = {
   .name = "nl80211 listener timer",
   .callback = _cb_transmission_event,
@@ -174,6 +176,8 @@ _init(void) {
     return -1;
   }
 
+  _l2_origin = oonf_layer2_register_origin();
+
   oonf_timer_add(&_transmission_timer_info);
 
   memset(_last_queried_if, 0, sizeof(_last_queried_if));
@@ -188,6 +192,8 @@ _init(void) {
  */
 static void
 _cleanup(void) {
+  oonf_layer2_unregister_origin(_l2_origin);
+
   oonf_timer_stop(&_transmission_timer);
   oonf_timer_remove(&_transmission_timer_info);
   os_system_netlink_remove(&_netlink_handler);
@@ -195,6 +201,27 @@ _cleanup(void) {
   free (_msgbuf);
 }
 
+static struct oonf_layer2_net *
+_create_l2net(struct netaddr *mac, int if_index, const char *if_name) {
+  struct oonf_layer2_net *net;
+  net = oonf_layer2_net_add(mac);
+  if (net == NULL) {
+    return NULL;
+  }
+
+  if (net->if_type ==  OONF_LAYER2_TYPE_UNDEFINED) {
+    net->if_type = OONF_LAYER2_TYPE_WIRELESS;
+    net->if_index = if_index;
+    strscpy(net->if_name, if_name, IF_NAMESIZE);
+  }
+  if (net->if_type !=  OONF_LAYER2_TYPE_WIRELESS) {
+    OONF_WARN(LOG_NL80211, "Wireless interface %s is already type %d",
+        if_name, net->if_type);
+    return NULL;
+  }
+  return net;
+}
+
 /**
  * Parse the netlink message result that contains the list of available
  * generic netlink families of the kernel.
@@ -303,10 +330,12 @@ _parse_cmd_new_station(struct nlmsghdr *hdr) {
   struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
 
   struct oonf_interface_data *if_data;
-  struct oonf_layer2_neighbor *neigh;
+  struct oonf_layer2_net *net;
+  struct oonf_layer2_neigh *neigh;
   struct netaddr mac;
   unsigned if_index;
   char if_name[IF_NAMESIZE];
+  int i;
 
 #ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str buf1, buf2;
@@ -343,58 +372,61 @@ _parse_cmd_new_station(struct nlmsghdr *hdr) {
   OONF_DEBUG(LOG_NL80211, "Add neighbor %s for network %s",
       netaddr_to_string(&buf1, &mac), netaddr_to_string(&buf2, &if_data->mac));
 
-  neigh = oonf_layer2_add_neighbor(&if_data->mac, &mac, if_index,
-      _config.interval + _config.interval / 4);
-  if (neigh == NULL) {
-    OONF_WARN(LOG_NL80211, "Not enough memory for new layer2 neighbor");
+  net = _create_l2net(&mac, if_data->index, if_name);
+  if (net == NULL) {
     return;
   }
 
-  /* make sure that the network is there */
-  oonf_layer2_add_network(&if_data->mac, if_index,
-        _config.interval + _config.interval / 4);
+  neigh = oonf_layer2_neigh_add(net, &mac);
+  if (neigh == NULL) {
+    return;
+  }
 
-  /* reset all existing data */
-  oonf_layer2_neighbor_clear(neigh);
+  /* remove old data */
+  for (i=0; i<OONF_LAYER2_NEIGH_COUNT; i++) {
+    oonf_layer2_reset_value(&neigh->data[i]);
+  }
+  neigh->last_seen = 0;
 
   /* insert new data */
   if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) {
-    oonf_layer2_neighbor_set_last_seen(neigh,
-        oonf_clock_get_absolute(nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME])));
+    neigh->last_seen = oonf_clock_get_absolute(nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]));
   }
   if (sinfo[NL80211_STA_INFO_RX_BYTES]) {
-    oonf_layer2_neighbor_set_rx_bytes(neigh,
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_RX_BYTES], _l2_origin,
         nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]));
   }
   if (sinfo[NL80211_STA_INFO_RX_PACKETS]) {
-    oonf_layer2_neighbor_set_rx_packets(neigh,
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_RX_FRAMES], _l2_origin,
         nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]));
   }
   if (sinfo[NL80211_STA_INFO_TX_BYTES]) {
-    oonf_layer2_neighbor_set_tx_bytes(neigh,
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_BYTES], _l2_origin,
         nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]));
   }
   if (sinfo[NL80211_STA_INFO_TX_PACKETS]) {
-    oonf_layer2_neighbor_set_tx_packets(neigh,
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_FRAMES], _l2_origin,
         nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]));
   }
   if (sinfo[NL80211_STA_INFO_TX_RETRIES])  {
-    oonf_layer2_neighbor_set_tx_retries(neigh,
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_RETRIES], _l2_origin,
         nla_get_u32(sinfo[NL80211_STA_INFO_TX_RETRIES]));
   }
   if (sinfo[NL80211_STA_INFO_TX_FAILED]) {
-    oonf_layer2_neighbor_set_tx_fails(neigh,
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_FAILED], _l2_origin,
         nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED]));
   }
   if (sinfo[NL80211_STA_INFO_SIGNAL])  {
-    oonf_layer2_neighbor_set_signal(neigh, (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]));
+    oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_SIGNAL], _l2_origin,
+        1000 * (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]));
   }
   if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
     if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
              sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy) == 0) {
       if (rinfo[NL80211_RATE_INFO_BITRATE]) {
-        uint64_t rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
-        oonf_layer2_neighbor_set_tx_bitrate(neigh, ((uint64_t)rate * 1024 * 1024) / 10);
+        int64_t rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
+        oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_BITRATE], _l2_origin,
+            (rate * 1024 * 1024) / 10);
       }
       /* TODO: do we need the rest of the data ? */
 #if 0
@@ -411,8 +443,9 @@ _parse_cmd_new_station(struct nlmsghdr *hdr) {
     if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
              sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy) == 0) {
       if (rinfo[NL80211_RATE_INFO_BITRATE]) {
-        uint64_t rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
-        oonf_layer2_neighbor_set_rx_bitrate(neigh, ((uint64_t)rate * 1024 * 1024) / 10);
+        int64_t rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
+        oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_RX_BITRATE], _l2_origin,
+            (rate * 1024 * 1024) / 10);
       }
       /* TODO: do we need the rest of the data ? */
 #if 0
@@ -426,7 +459,7 @@ _parse_cmd_new_station(struct nlmsghdr *hdr) {
     }
   }
 
-  oonf_layer2_neighbor_commit(neigh);
+  oonf_layer2_neigh_commit(neigh);
   return;
 }
 
@@ -439,7 +472,8 @@ _parse_cmd_del_station(struct nlmsghdr *hdr) {
   struct nlattr *tb[NL80211_ATTR_MAX + 1];
 
   struct oonf_interface_data *if_data;
-  struct oonf_layer2_neighbor *neigh;
+  struct oonf_layer2_neigh *neigh;
+  struct oonf_layer2_net *net;
   struct netaddr mac;
   unsigned if_index;
   char if_name[IF_NAMESIZE];
@@ -467,9 +501,14 @@ _parse_cmd_del_station(struct nlmsghdr *hdr) {
   OONF_DEBUG(LOG_NL80211, "Remove neighbor %s for network %s",
       netaddr_to_string(&buf1, &mac), netaddr_to_string(&buf2, &if_data->mac));
 
-  neigh = oonf_layer2_get_neighbor(&if_data->mac, &mac);
+  net = oonf_layer2_net_get(&if_data->mac);
+  if (net == NULL) {
+    return;
+  }
+
+  neigh = oonf_layer2_neigh_get(net, &mac);
   if (neigh != NULL) {
-    oonf_layer2_remove_neighbor(neigh);
+    oonf_layer2_neigh_remove(neigh, _l2_origin);
   }
 }
 
@@ -511,10 +550,11 @@ _parse_cmd_new_scan_result(struct nlmsghdr *msg) {
   struct nlattr *bss[NL80211_BSS_MAX + 1];
 
   struct oonf_interface_data *if_data;
-  struct oonf_layer2_network *net;
+  struct oonf_layer2_net *net;
   struct netaddr mac;
   unsigned if_index;
   char if_name[IF_NAMESIZE];
+  int i;
 #ifdef OONF_LOG_DEBUG_INFO
   struct netaddr_str buf;
 #endif
@@ -557,13 +597,17 @@ _parse_cmd_new_scan_result(struct nlmsghdr *msg) {
     return;
   }
 
-  net = oonf_layer2_add_network(&if_data->mac, if_index,
-      _config.interval + _config.interval / 4);
+  net = _create_l2net(&mac, if_data->index, if_name);
   if (net == NULL) {
-    OONF_WARN(LOG_NL80211, "Not enough memory for new layer2 network");
     return;
   }
 
+  /* remove old data */
+  for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
+    oonf_layer2_reset_value(&net->data[i]);
+  }
+  net->last_seen = 0;
+
   OONF_DEBUG(LOG_NL80211, "Add network %s", netaddr_to_string(&buf, &if_data->mac));
 #if 0
   if (bss[NL80211_BSS_STATUS]) {
@@ -595,8 +639,8 @@ _parse_cmd_new_scan_result(struct nlmsghdr *msg) {
 #endif
 
   if (bss[NL80211_BSS_FREQUENCY]) {
-    oonf_layer2_network_set_frequency(net,
-        nla_get_u32(bss[NL80211_BSS_FREQUENCY]) * 1000000ull);
+    oonf_layer2_set_value(&net->data[OONF_LAYER2_NET_FREQUENCY], _l2_origin,
+        nla_get_u32(bss[NL80211_BSS_FREQUENCY]) * 1000000ll);
   }
 #if 0
   if (bss[NL80211_BSS_BEACON_INTERVAL])
@@ -639,18 +683,15 @@ _parse_cmd_new_scan_result(struct nlmsghdr *msg) {
   }
 #endif
   if (bss[NL80211_BSS_SEEN_MS_AGO]) {
-    oonf_layer2_network_set_last_seen(net,
-        nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]));
+    net->last_seen = oonf_clock_get_absolute(nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]));
   }
   if (bss[NL80211_BSS_INFORMATION_ELEMENTS] != NULL ||
       bss[NL80211_BSS_BEACON_IES] != NULL) {
-    int len,i;
+    int len;
     uint8_t *data;
-    uint8_t *rate1, *rate2;
-    uint8_t rate1_count, rate2_count;
-    uint64_t *rate;
+    int64_t rate, max_rate;
 
-    rate1 = rate2 = NULL;
+    max_rate = 0;
 
     if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
       len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@@ -662,49 +703,39 @@ _parse_cmd_new_scan_result(struct nlmsghdr *msg) {
     }
 
     /* collect pointers to data-rates */
-    rate1_count = 0;
-    rate2_count = 0;
     while (len > 0) {
       if (data[0] == 0) {
         /* SSID */
-        char ssid[33];
-
-        memset(ssid, 0, sizeof(ssid));
-        memcpy(ssid, &data[2], data[1]);
-        oonf_layer2_network_set_ssid(net, ssid);
+        strscpy(net->if_ident, (const char *)(&data[2]), data[1]);
       }
       if (data[0] == 1) {
         /* supported rates */
-        rate1 = &data[2];
-        rate1_count = data[1];
+        for (i=0; i<data[1]; i++) {
+          rate = (data[2+i] & 0x7f) << 19;
+          if (rate > max_rate) {
+            max_rate = rate;
+          }
+        }
       }
       else if (data[0] == 50) {
         /* extended supported rates */
-        rate2 = &data[2];
-        rate2_count = data[1];
+        for (i=0; i<data[1]; i++) {
+          rate = (data[2+i] & 0x7f) << 19;
+          if (rate > max_rate) {
+            max_rate = rate;
+          }
+        }
       }
       len -= data[1] + 2;
       data += data[1] + 2;
     }
 
-    if (rate1_count + rate2_count > 0) {
-      rate = calloc(rate1_count + rate2_count, sizeof(uint64_t));
-      if (rate) {
-        len = 0;
-        for (i=0; i<rate1_count; i++) {
-          rate[len++] = (uint64_t)(rate1[i] & 0x7f) << 19;
-        }
-        for (i=0; i<rate2_count; i++) {
-          rate[len++] = (uint64_t)(rate2[i] & 0x7f) << 19;
-        }
-
-        oonf_layer2_network_set_supported_rates(net, rate, rate1_count + rate2_count);
-        free(rate);
-      }
+    if (max_rate) {
+      oonf_layer2_set_value(&net->data[OONF_LAYER2_NET_MAX_BITRATE], _l2_origin, max_rate);
     }
   }
 
-  oonf_layer2_network_commit(net);
+  oonf_layer2_net_commit(net);
   return;
 }
 
@@ -891,6 +922,5 @@ _cb_config_changed(void) {
     return;
   }
 
-  /* half of them station dumps, half of them passive scans */
-  oonf_timer_start(&_transmission_timer, _config.interval);
+  oonf_timer_set_ext(&_transmission_timer, 1, _config.interval);
 }