Track scaling factors of layer2 data elements.
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 29 May 2018 08:20:45 +0000 (10:20 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 29 May 2018 08:20:45 +0000 (10:20 +0200)
Handle different scaling for DLEP conversion.

31 files changed:
include/oonf/base/oonf_layer2.h
include/oonf/generic/dlep/dlep_extension.h
include/oonf/generic/dlep/dlep_reader.h
include/oonf/generic/dlep/dlep_writer.h
include/oonf/generic/nl80211_listener/nl80211_listener.h
include/oonf/libcommon/isonumber.h
include/oonf/libconfig/cfg_schema.h
src/base/oonf_layer2.c
src/generic/dlep/dlep_extension.c
src/generic/dlep/dlep_reader.c
src/generic/dlep/dlep_writer.c
src/generic/dlep/ext_base_metric/metric.c
src/generic/dlep/ext_base_proto/proto.c
src/generic/dlep/ext_l1_statistics/l1_statistics.c
src/generic/dlep/ext_l2_statistics/l2_statistics.c
src/generic/dlep/radio/dlep_radio_interface.c
src/generic/eth_listener/eth_listener.c
src/generic/layer2_config/layer2_config.c
src/generic/layer2_generator/layer2_generator.c
src/generic/link_config/link_config.c
src/generic/nl80211_listener/nl80211_get_interface.c
src/generic/nl80211_listener/nl80211_get_station_dump.c
src/generic/nl80211_listener/nl80211_get_survey.c
src/generic/nl80211_listener/nl80211_get_wiphy.c
src/generic/nl80211_listener/nl80211_listener.c
src/libcommon/isonumber.c
src/libconfig/cfg_tobin.c
src/libconfig/cfg_validate.c
src/nhdp/ff_dat_metric/ff_dat_metric.c
src/nhdp/neighbor_probing/neighbor_probing.c
src/tests/common/test_common_isonumber.c

index a7e86e4..ed7508e 100644 (file)
@@ -156,9 +156,11 @@ enum {
 enum oonf_layer2_origin_priority
 {
   OONF_LAYER2_ORIGIN_UNKNOWN = 0,
-  OONF_LAYER2_ORIGIN_UNRELIABLE = 10,
-  OONF_LAYER2_ORIGIN_CONFIGURED = 20,
-  OONF_LAYER2_ORIGIN_RELIABLE = 30,
+  OONF_LAYER2_ORIGIN_DEFAULT = 10,
+  OONF_LAYER2_ORIGIN_UNRELIABLE = 20,
+  OONF_LAYER2_ORIGIN_CONFIGURED = 30,
+  OONF_LAYER2_ORIGIN_RELIABLE = 40,
+  OONF_LAYER2_ORIGIN_OVERWRITE = 50,
 };
 
 /**
@@ -185,7 +187,6 @@ struct oonf_layer2_origin {
 
 enum oonf_layer2_data_type
 {
-  OONF_LAYER2_NO_DATA,
   OONF_LAYER2_INTEGER_DATA,
   OONF_LAYER2_BOOLEAN_DATA,
   OONF_LAYER2_NETWORK_DATA,
@@ -200,20 +201,6 @@ union oonf_layer2_value {
 };
 
 /**
- * Single data entry of layer2 network or neighbor
- */
-struct oonf_layer2_data {
-  /*! data value */
-  union oonf_layer2_value _value;
-
-  /*! type of data contained in this element */
-  enum oonf_layer2_data_type _type;
-
-  /*! layer2 originator id */
-  const struct oonf_layer2_origin *_origin;
-};
-
-/**
  * Metadata of layer2 data entry for automatic processing
  */
 struct oonf_layer2_metadata {
@@ -226,8 +213,22 @@ struct oonf_layer2_metadata {
   /*! unit (bit/s, byte, ...) */
   const char unit[8];
 
-  /*! number of fractional digits of the data */
-  const int fraction;
+  /*! scaling factor for  */
+  const uint64_t scaling;
+};
+
+/**
+ * Single data entry of layer2 network or neighbor
+ */
+struct oonf_layer2_data {
+  /*! data value */
+  union oonf_layer2_value _value;
+
+  /*! metadata corresponding to this data */
+  const struct oonf_layer2_metadata *_meta;
+
+  /*! layer2 originator id */
+  const struct oonf_layer2_origin *_origin;
 };
 
 /**
@@ -588,12 +589,14 @@ EXPORT int oonf_layer2_data_parse_string(
 EXPORT const char *oonf_layer2_data_to_string(
   char *buffer, size_t length, const struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta, bool raw);
 EXPORT bool oonf_layer2_data_set(struct oonf_layer2_data *data, const struct oonf_layer2_origin *origin,
-  enum oonf_layer2_data_type type, const union oonf_layer2_value *input);
+  const struct oonf_layer2_metadata *meta, const union oonf_layer2_value *input);
+EXPORT bool oonf_layer2_data_set_int64(struct oonf_layer2_data *l2data, const struct oonf_layer2_origin *origin,
+  const struct oonf_layer2_metadata *meta, int64_t integer, uint64_t scaling);
 EXPORT bool oonf_layer2_data_compare(const union oonf_layer2_value *left, const union oonf_layer2_value *right,
   enum oonf_layer2_data_comparator_type comparator, enum oonf_layer2_data_type data_type);
 EXPORT enum oonf_layer2_data_comparator_type oonf_layer2_data_get_comparator(const char *);
 EXPORT const char *oonf_layer2_data_get_comparator_string(enum oonf_layer2_data_comparator_type type);
-EXPORT const char *oonf_layer2_data_get_type_string(enum oonf_layer2_data_type type);
+EXPORT const char *oonf_layer2_data_get_type_string(const struct oonf_layer2_metadata *meta);
 
 EXPORT struct oonf_layer2_net *oonf_layer2_net_add(const char *ifname);
 EXPORT bool oonf_layer2_net_remove(struct oonf_layer2_net *, const struct oonf_layer2_origin *origin);
@@ -796,7 +799,7 @@ oonf_layer2_destination_get(const struct oonf_layer2_neigh *l2neigh, const struc
  */
 static INLINE bool
 oonf_layer2_data_has_value(const struct oonf_layer2_data *l2data) {
-  return l2data->_type != OONF_LAYER2_NO_DATA;
+  return l2data->_origin != NULL && l2data->_meta != NULL;
 }
 
 /**
@@ -805,61 +808,72 @@ oonf_layer2_data_has_value(const struct oonf_layer2_data *l2data) {
  */
 static INLINE enum oonf_layer2_data_type
 oonf_layer2_data_get_type(const struct oonf_layer2_data *l2data) {
-  return l2data->_type;
+  return l2data->_meta->type;
 }
 
 /**
+ * @param buffer pointer to int64 data storage
  * @param l2data layer-2 data object
- * @param def default value to return
- * @return value of data object, default value if not net
+ * @param scale scaling factor of the decimal point, 0 to keep data scaling
+ * @return 0 if value was read, -1 if it was the wrong type
  */
-static INLINE int64_t
-oonf_layer2_data_get_int64(const struct oonf_layer2_data *l2data, int64_t def) {
-  if (l2data->_type != OONF_LAYER2_INTEGER_DATA) {
-    return def;
+static INLINE int
+oonf_layer2_data_read_int64(int64_t *buffer, const struct oonf_layer2_data *l2data, uint64_t scale) {
+  if (!oonf_layer2_data_has_value(l2data)
+      || oonf_layer2_data_get_type(l2data) != OONF_LAYER2_INTEGER_DATA) {
+    return -1;
+  }
+  if (!scale) {
+    scale = l2data->_meta->scaling;
+  }
+  if (scale > l2data->_meta->scaling) {
+    *buffer =  l2data->_value.integer * (scale / l2data->_meta->scaling);
+  }
+  else {
+    *buffer = l2data->_value.integer / (l2data->_meta->scaling / scale);
   }
-  return l2data->_value.integer;
+  return 0;
 }
 
 /**
  * @param l2data layer-2 data object
+ * @param scale scaling factor of the decimal point
  * @param def default value to return
  * @return value of data object, default value if not net
  */
-static INLINE bool
-oonf_layer2_data_get_boolean(const struct oonf_layer2_data *l2data, bool def) {
-  if (l2data->_type != OONF_LAYER2_BOOLEAN_DATA) {
-    return def;
-  }
-  return l2data->_value.boolean;
+static INLINE int64_t
+oonf_layer2_data_get_int64(const struct oonf_layer2_data *l2data, uint64_t scale, int64_t def) {
+  int64_t result = def;
+
+  oonf_layer2_data_read_int64(&result, l2data, scale);
+  return result;
 }
 
 /**
- * @param buffer pointer to int64 data storage
+ * @param buffer pointer to boolean data storage
  * @param l2data layer-2 data object
  * @return 0 if value was read, -1 if it was the wrong type
  */
 static INLINE int
-oonf_layer2_data_read_int64(int64_t *buffer, const struct oonf_layer2_data *l2data) {
-  if (l2data->_type != OONF_LAYER2_INTEGER_DATA) {
+oonf_layer2_data_read_boolean(bool *buffer, const struct oonf_layer2_data *l2data) {
+  if (!l2data->_meta ||  oonf_layer2_data_get_type(l2data) != OONF_LAYER2_BOOLEAN_DATA) {
     return -1;
   }
-  *buffer = l2data->_value.integer;
+  *buffer = l2data->_value.boolean;
   return 0;
 }
 
 /**
- * @param buffer pointer to boolean data storage
  * @param l2data layer-2 data object
- * @return 0 if value was read, -1 if it was the wrong type
+ * @param def default value to return
+ * @return value of data object, default value if not net
  */
-static INLINE int
-oonf_layer2_data_read_boolean(bool *buffer, const struct oonf_layer2_data *l2data) {
-  if (l2data->_type != OONF_LAYER2_BOOLEAN_DATA) {
-    return -1;
-  }
-  *buffer = l2data->_value.boolean;
-  return 0;
+static INLINE bool
+oonf_layer2_data_get_boolean(const struct oonf_layer2_data *l2data, bool def) {
+  bool result = def;
+
+  oonf_layer2_data_read_boolean(&result, l2data);
+  return result;
 }
 
 /**
@@ -889,7 +903,7 @@ oonf_layer2_data_from_string(struct oonf_layer2_data *data, const struct oonf_la
   if (oonf_layer2_data_parse_string(&value, meta, input)) {
     return false;
   }
-  return oonf_layer2_data_set(data, origin, meta->type, &value);
+  return oonf_layer2_data_set(data, origin, meta, &value);
 }
 
 static INLINE const char *
@@ -908,29 +922,16 @@ oonf_layer2_neigh_data_to_string(
  * Set the value of a layer-2 data object
  * @param l2data layer-2 data object
  * @param origin originator of value
- * @param integer new value for data object
- * @return true if value was overwrite, false otherwise
- */
-static INLINE bool
-oonf_layer2_data_set_int64(struct oonf_layer2_data *l2data, const struct oonf_layer2_origin *origin, int64_t integer) {
-  union oonf_layer2_value value = { 0 };
-  value.integer = integer;
-
-  return oonf_layer2_data_set(l2data, origin, OONF_LAYER2_INTEGER_DATA, &value);
-}
-
-/**
- * Set the value of a layer-2 data object
- * @param l2data layer-2 data object
- * @param origin originator of value
+ * @param meta layer2 metadata, NULL for same metadata as l2data object
  * @param boolean new value for data object
  * @return true if value was overwrite, false otherwise
  */
 static INLINE bool
-oonf_layer2_data_set_bool(struct oonf_layer2_data *l2data, const struct oonf_layer2_origin *origin, bool boolean) {
+oonf_layer2_data_set_bool(struct oonf_layer2_data *l2data, const struct oonf_layer2_origin *origin,
+    const struct oonf_layer2_metadata *meta, bool boolean) {
   union oonf_layer2_value value = { 0 };
   value.boolean = boolean;
-  return oonf_layer2_data_set(l2data, origin, OONF_LAYER2_BOOLEAN_DATA, &value);
+  return oonf_layer2_data_set(l2data, origin, meta, &value);
 }
 
 static INLINE int
@@ -951,7 +952,7 @@ oonf_layer2_neigh_data_from_string(struct oonf_layer2_data *data, enum oonf_laye
  */
 static INLINE void
 oonf_layer2_data_reset(struct oonf_layer2_data *l2data) {
-  l2data->_type = OONF_LAYER2_NO_DATA;
+  l2data->_meta = NULL;
   l2data->_origin = NULL;
 }
 
index c7a6579..4f47f89 100644 (file)
@@ -171,6 +171,9 @@ struct dlep_neighbor_mapping {
   /*! binary length of tlv */
   uint16_t length;
 
+  /* fixed integer arithmetics scaling factor */
+  uint64_t scaling;
+
   /*! layer2 neighbor id */
   enum oonf_layer2_neighbor_index layer2;
 
@@ -186,10 +189,11 @@ struct dlep_neighbor_mapping {
    * @param meta metadata description for data
    * @param session dlep session
    * @param tlv tlv id
+   * @param scaling fixed integer arithmetics scaling factor
    * @return -1 if an error happened, 0 otherwise
    */
   int (*from_tlv)(struct oonf_layer2_data *l2data, const struct oonf_layer2_metadata *meta,
-    struct dlep_session *session, uint16_t tlv);
+    struct dlep_session *session, uint16_t tlv, uint64_t scaling);
 
   /**
    * callback to transform layer2 data into a DLEP tlv
@@ -198,10 +202,11 @@ struct dlep_neighbor_mapping {
    * @param meta metadata description for data
    * @param tlv tlv id
    * @param length tlv length
+   * @param scaling fixed integer arithmetics scaling factor
    * @return -1 if an error happened, 0 otherwise
    */
   int (*to_tlv)(struct dlep_writer *writer, struct oonf_layer2_data *l2data, const struct oonf_layer2_metadata *meta,
-    uint16_t tlv, uint16_t length);
+    uint16_t tlv, uint16_t length, uint64_t scaling);
 };
 
 /**
@@ -215,6 +220,9 @@ struct dlep_network_mapping {
   /*! binary length of tlv */
   uint16_t length;
 
+  /* fixed integer arithmetics scaling factor */
+  uint64_t scaling;
+
   /*! layer2 network index */
   enum oonf_layer2_network_index layer2;
 
@@ -230,10 +238,11 @@ struct dlep_network_mapping {
    * @param meta metadata description for data
    * @param session dlep session
    * @param tlv tlv id
+   * @param scaling fixed integer arithmetics scaling factor
    * @return -1 if an error happened, 0 otherwise
    */
   int (*from_tlv)(struct oonf_layer2_data *l2data, const struct oonf_layer2_metadata *meta,
-    struct dlep_session *session, uint16_t tlv);
+    struct dlep_session *session, uint16_t tlv, uint64_t scaling);
 
   /**
    * callback to transform layer2 data into a DLEP tlv
@@ -242,10 +251,11 @@ struct dlep_network_mapping {
    * @param meta metadata description for data
    * @param tlv tlv id
    * @param length tlv length
+   * @param scaling fixed integer arithmetics scaling factor
    * @return -1 if an error happened, 0 otherwise
    */
   int (*to_tlv)(struct dlep_writer *writer, struct oonf_layer2_data *l2data, const struct oonf_layer2_metadata *meta,
-    uint16_t tlv, uint16_t length);
+    uint16_t tlv, uint16_t length, uint64_t scaling);
 };
 
 /**
index 193d770..a304142 100644 (file)
@@ -78,7 +78,7 @@ int dlep_reader_status(enum dlep_status *status, char *text, size_t text_length,
   struct dlep_parser_value *value);
 
 int dlep_reader_map_identity(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv);
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling);
 int dlep_reader_map_l2neigh_data(
   struct oonf_layer2_data *data, struct dlep_session *session, struct dlep_extension *ext);
 int dlep_reader_map_l2net_data(struct oonf_layer2_data *data, struct dlep_session *session, struct dlep_extension *ext);
index 540ddcd..f6cb4a4 100644 (file)
@@ -73,7 +73,7 @@ int dlep_writer_add_status(struct dlep_writer *writer, enum dlep_status status,
 void dlep_writer_add_supported_extensions(struct dlep_writer *writer, const uint16_t *extensions, uint16_t ext_count);
 
 int dlep_writer_map_identity(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length);
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling);
 int dlep_writer_map_l2neigh_data(
   struct dlep_writer *writer, struct dlep_extension *ext, struct oonf_layer2_data *data, struct oonf_layer2_data *def);
 int dlep_writer_map_l2net_data(struct dlep_writer *writer, struct dlep_extension *ext, struct oonf_layer2_data *data);
index 10acf62..451e9c0 100644 (file)
@@ -93,12 +93,13 @@ struct nl80211_if {
 };
 
 struct oonf_layer2_destination *nl80211_add_dst(struct oonf_layer2_neigh *, const struct netaddr *dst);
-bool nl80211_change_l2net_data(struct oonf_layer2_net *l2net, enum oonf_layer2_network_index idx, uint64_t value);
+bool nl80211_change_l2net_data(struct oonf_layer2_net *l2net, enum oonf_layer2_network_index idx,
+                               int64_t value, int64_t scaling);
 bool nl80211_change_l2net_neighbor_default(
-  struct oonf_layer2_net *l2net, enum oonf_layer2_neighbor_index idx, uint64_t value);
+  struct oonf_layer2_net *l2net, enum oonf_layer2_neighbor_index idx, int64_t value, int64_t scaling);
 void nl80211_cleanup_l2neigh_data(struct oonf_layer2_neigh *l2neigh);
 bool nl80211_change_l2neigh_data(
-  struct oonf_layer2_neigh *l2neigh, enum oonf_layer2_neighbor_index idx, uint64_t value);
+  struct oonf_layer2_neigh *l2neigh, enum oonf_layer2_neighbor_index idx, int64_t value, int64_t scaling);
 bool nl80211_create_broadcast_neighbor(void);
 
 /**
index 7ea106d..d3dd95f 100644 (file)
@@ -58,10 +58,10 @@ struct isonumber_str {
 };
 
 EXPORT const char *isonumber_from_u64(
-  struct isonumber_str *out, uint64_t number, const char *unit, int fraction, bool raw);
+  struct isonumber_str *out, uint64_t number, const char *unit, uint64_t scaling, bool raw);
 EXPORT const char *isonumber_from_s64(
-  struct isonumber_str *out, int64_t number, const char *unit, int fraction, bool raw);
-EXPORT int isonumber_to_u64(uint64_t *dst, const char *iso, int fractions);
-EXPORT int isonumber_to_s64(int64_t *dst, const char *iso, int fractions);
+  struct isonumber_str *out, int64_t number, const char *unit, uint64_t scaling, bool raw);
+EXPORT int isonumber_to_u64(uint64_t *dst, const char *iso, uint64_t scaling);
+EXPORT int isonumber_to_s64(int64_t *dst, const char *iso, uint64_t scaling);
 
 #endif /* ISONUMBER_H_ */
index fba7856..a2070ba 100644 (file)
@@ -1316,6 +1316,9 @@ struct cfg_schema_token_customizer {
    * @param out buffer for help text output
    */
   void (*cb_valhelp)(const struct cfg_schema_entry *entry, struct autobuf *out);
+
+  /*! number of optional arguments at the end of the chain of tokens */
+  uint32_t optional;
 };
 
 /*! List of strings that are considered valid boolean options */
index 6381e3c..36ec962 100644 (file)
@@ -82,50 +82,50 @@ DECLARE_OONF_PLUGIN(_oonf_layer2_subsystem);
 
 /* layer2 neighbor metadata */
 static const struct oonf_layer2_metadata _metadata_neigh[OONF_LAYER2_NEIGH_COUNT] = {
-  [OONF_LAYER2_NEIGH_TX_SIGNAL] = { .key = "tx_signal", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dBm", .fraction = 3 },
-  [OONF_LAYER2_NEIGH_RX_SIGNAL] = { .key = "rx_signal", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dBm", .fraction = 3 },
-  [OONF_LAYER2_NEIGH_TX_SNR] = { .key = "tx_snr", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dB", .fraction = 3 },
-  [OONF_LAYER2_NEIGH_RX_SNR] = { .key = "rx_snr", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dB", .fraction = 3 },
-  [OONF_LAYER2_NEIGH_TX_BITRATE] = { .key = "tx_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_RX_BITRATE] = { .key = "rx_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_TX_MAX_BITRATE] = { .key = "tx_max_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_RX_MAX_BITRATE] = { .key = "rx_max_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_TX_BYTES] = { .key = "tx_bytes", .type = OONF_LAYER2_INTEGER_DATA, .unit = "byte" },
-  [OONF_LAYER2_NEIGH_RX_BYTES] = { .key = "rx_bytes", .type = OONF_LAYER2_INTEGER_DATA, .unit = "byte" },
-  [OONF_LAYER2_NEIGH_TX_FRAMES] = { .key = "tx_frames", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_RX_FRAMES] = { .key = "rx_frames", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_TX_THROUGHPUT] = { .key = "tx_throughput", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_RX_THROUGHPUT] = { .key = "rx_throughput", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_TX_RETRIES] = { .key = "tx_retries", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_RX_RETRIES] = { .key = "rx_retries", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_TX_FAILED] = { .key = "tx_failed", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_RX_FAILED] = { .key = "rx_failed", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_TX_RLQ] = { .key = "tx_rlq", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_RX_RLQ] = { .key = "rx_rlq", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_RX_BC_BITRATE] = { .key = "rx_bc_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NEIGH_RX_BC_LOSS] = { .key = "rx_bc_loss", .type = OONF_LAYER2_INTEGER_DATA, .fraction = 3 },
-  [OONF_LAYER2_NEIGH_LATENCY] = { .key = "latency", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .fraction = 6 },
-  [OONF_LAYER2_NEIGH_RESOURCES] = { .key = "resources", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_RADIO_HOPCOUNT] = { .key = "radio_hopcount", .type = OONF_LAYER2_INTEGER_DATA },
-  [OONF_LAYER2_NEIGH_IP_HOPCOUNT] = { .key = "ip_hopcount", .type = OONF_LAYER2_INTEGER_DATA },
+  [OONF_LAYER2_NEIGH_TX_SIGNAL] = { .key = "tx_signal", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dBm", .scaling = 1000 },
+  [OONF_LAYER2_NEIGH_RX_SIGNAL] = { .key = "rx_signal", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dBm", .scaling = 1000 },
+  [OONF_LAYER2_NEIGH_TX_SNR] = { .key = "tx_snr", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dB", .scaling = 1000 },
+  [OONF_LAYER2_NEIGH_RX_SNR] = { .key = "rx_snr", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dB", .scaling = 1000 },
+  [OONF_LAYER2_NEIGH_TX_BITRATE] = { .key = "tx_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_BITRATE] = { .key = "rx_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_MAX_BITRATE] = { .key = "tx_max_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_MAX_BITRATE] = { .key = "rx_max_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_BYTES] = { .key = "tx_bytes", .type = OONF_LAYER2_INTEGER_DATA, .unit = "byte", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_BYTES] = { .key = "rx_bytes", .type = OONF_LAYER2_INTEGER_DATA, .unit = "byte", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_FRAMES] = { .key = "tx_frames", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_FRAMES] = { .key = "rx_frames", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_THROUGHPUT] = { .key = "tx_throughput", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_THROUGHPUT] = { .key = "rx_throughput", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_RETRIES] = { .key = "tx_retries", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_RETRIES] = { .key = "rx_retries", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_FAILED] = { .key = "tx_failed", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_FAILED] = { .key = "rx_failed", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_TX_RLQ] = { .key = "tx_rlq", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_RLQ] = { .key = "rx_rlq", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_BC_BITRATE] = { .key = "rx_bc_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RX_BC_LOSS] = { .key = "rx_bc_loss", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1000 },
+  [OONF_LAYER2_NEIGH_LATENCY] = { .key = "latency", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .scaling = 1000000 },
+  [OONF_LAYER2_NEIGH_RESOURCES] = { .key = "resources", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_RADIO_HOPCOUNT] = { .key = "radio_hopcount", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
+  [OONF_LAYER2_NEIGH_IP_HOPCOUNT] = { .key = "ip_hopcount", .type = OONF_LAYER2_INTEGER_DATA, .scaling = 1 },
 };
 
 /* layer2 network metadata */
 static const struct oonf_layer2_metadata _metadata_net[OONF_LAYER2_NET_COUNT] = {
-  [OONF_LAYER2_NET_FREQUENCY_1] = { .key = "frequency1", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz" },
-  [OONF_LAYER2_NET_FREQUENCY_2] = { .key = "frequency2", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz" },
-  [OONF_LAYER2_NET_BANDWIDTH_1] = { .key = "bandwidth1", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz" },
-  [OONF_LAYER2_NET_BANDWIDTH_2] = { .key = "bandwidth2", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz" },
-  [OONF_LAYER2_NET_NOISE] = { .key = "noise", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dBm", .fraction = 3 },
+  [OONF_LAYER2_NET_FREQUENCY_1] = { .key = "frequency1", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz", .scaling = 1 },
+  [OONF_LAYER2_NET_FREQUENCY_2] = { .key = "frequency2", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz", .scaling = 1 },
+  [OONF_LAYER2_NET_BANDWIDTH_1] = { .key = "bandwidth1", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz", .scaling = 1 },
+  [OONF_LAYER2_NET_BANDWIDTH_2] = { .key = "bandwidth2", .type = OONF_LAYER2_INTEGER_DATA, .unit = "Hz", .scaling = 1 },
+  [OONF_LAYER2_NET_NOISE] = { .key = "noise", .type = OONF_LAYER2_INTEGER_DATA, .unit = "dBm", .scaling = 1000 },
   [OONF_LAYER2_NET_CHANNEL_ACTIVE] = { .key = "ch_active",
     .type = OONF_LAYER2_INTEGER_DATA,
     .unit = "s",
-    .fraction = 9 },
-  [OONF_LAYER2_NET_CHANNEL_BUSY] = { .key = "ch_busy", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .fraction = 9 },
-  [OONF_LAYER2_NET_CHANNEL_RX] = { .key = "ch_rx", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .fraction = 9 },
-  [OONF_LAYER2_NET_CHANNEL_TX] = { .key = "ch_tx", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .fraction = 9 },
-  [OONF_LAYER2_NET_TX_BC_BITRATE] = { .key = "tx_bc_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s" },
-  [OONF_LAYER2_NET_MTU] = { .key = "mtu", .type = OONF_LAYER2_INTEGER_DATA, .unit = "byte" },
+    .scaling = 1000000000 },
+  [OONF_LAYER2_NET_CHANNEL_BUSY] = { .key = "ch_busy", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .scaling = 1000000000 },
+  [OONF_LAYER2_NET_CHANNEL_RX] = { .key = "ch_rx", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .scaling = 1000000000 },
+  [OONF_LAYER2_NET_CHANNEL_TX] = { .key = "ch_tx", .type = OONF_LAYER2_INTEGER_DATA, .unit = "s", .scaling = 1000000000 },
+  [OONF_LAYER2_NET_TX_BC_BITRATE] = { .key = "tx_bc_bitrate", .type = OONF_LAYER2_INTEGER_DATA, .unit = "bit/s", .scaling = 1 },
+  [OONF_LAYER2_NET_MTU] = { .key = "mtu", .type = OONF_LAYER2_INTEGER_DATA, .unit = "byte", .scaling = 1 },
   [OONF_LAYER2_NET_MCS_BY_PROBING] = { .key = "mcs_by_probing", .type = OONF_LAYER2_BOOLEAN_DATA },
   [OONF_LAYER2_NET_RX_ONLY_UNICAST] = { .key = "rx_only_unicast", .type = OONF_LAYER2_BOOLEAN_DATA },
   [OONF_LAYER2_NET_TX_ONLY_UNICAST] = { .key = "tx_only_unicast", .type = OONF_LAYER2_BOOLEAN_DATA },
@@ -150,7 +150,6 @@ static const char *_data_comparators[OONF_LAYER2_DATA_CMP_COUNT] = {
 };
 
 static const char *_data_types[OONF_LAYER2_DATA_TYPE_COUNT] = {
-  [OONF_LAYER2_NO_DATA] = "none",
   [OONF_LAYER2_INTEGER_DATA] = "integer",
   [OONF_LAYER2_BOOLEAN_DATA] = "boolean",
   [OONF_LAYER2_NETWORK_DATA] = "network",
@@ -286,7 +285,7 @@ oonf_layer2_data_parse_string(
 
   switch (meta->type) {
     case OONF_LAYER2_INTEGER_DATA:
-      return isonumber_to_s64(&value->integer, input, meta->fraction);
+      return isonumber_to_s64(&value->integer, input, meta->scaling);
 
     case OONF_LAYER2_BOOLEAN_DATA:
       if (!cfg_is_bool(input)) {
@@ -316,7 +315,7 @@ oonf_layer2_data_to_string(
 
   switch (meta->type) {
     case OONF_LAYER2_INTEGER_DATA:
-      if (!isonumber_from_s64(&iso_str, data->_value.integer, meta->unit, meta->fraction, raw)) {
+      if (!isonumber_from_s64(&iso_str, data->_value.integer, meta->unit, meta->scaling, raw)) {
         return NULL;
       }
       return strscpy(buffer, iso_str.buf, length);
@@ -333,26 +332,60 @@ oonf_layer2_data_to_string(
  * (Over)write the value of a layer2 data object
  * @param l2data layer2 data object
  * @param origin origin of new data
- * @param type type of new data
+ * @param meta metainformation of data
  * @param input new data value
  * @return true if data changed, false otherwise
  */
 bool
 oonf_layer2_data_set(struct oonf_layer2_data *l2data, const struct oonf_layer2_origin *origin,
-  enum oonf_layer2_data_type type, const union oonf_layer2_value *input) {
+  const struct oonf_layer2_metadata *meta, const union oonf_layer2_value *input) {
   bool changed = false;
 
-  if (l2data->_type == OONF_LAYER2_NO_DATA || l2data->_origin == NULL || l2data->_origin == origin ||
+  if (meta == NULL) {
+    OONF_ASSERT(l2data->_meta != NULL, LOG_LAYER2, "Tried to set layer2 data without metadata (origin: %s)", origin->name);
+    meta = l2data->_meta;
+  }
+  if (l2data->_meta == NULL || l2data->_origin == NULL || l2data->_origin == origin ||
       l2data->_origin->priority < origin->priority) {
-    changed = l2data->_type != type || memcmp(&l2data->_value, input, sizeof(*input)) != 0;
+    changed = l2data->_meta != meta || memcmp(&l2data->_value, input, sizeof(*input)) != 0;
     memcpy(&l2data->_value, input, sizeof(*input));
-    l2data->_type = type;
+    l2data->_meta = meta;
     l2data->_origin = origin;
   }
   return changed;
 }
 
 /**
+ * Set the value of a layer-2 data object
+ * @param l2data layer-2 data object
+ * @param origin originator of value
+ * @param integer new value for data object
+ * @param scaling scaling of the fixpoint interger arithmetics, 0 for same as metadata
+ * @return true if value was overwrite, false otherwise
+ */
+bool
+oonf_layer2_data_set_int64(struct oonf_layer2_data *l2data, const struct oonf_layer2_origin *origin,
+    const struct oonf_layer2_metadata *meta, int64_t integer, uint64_t scaling) {
+  union oonf_layer2_value value = { 0 };
+
+  if (meta == NULL) {
+    OONF_ASSERT(l2data->_meta != NULL, LOG_LAYER2, "Tried to set layer2 data without metadata (origin: %s)", origin->name);
+    meta = l2data->_meta;
+  }
+  if (scaling == 0) {
+    value.integer = integer;
+  }
+  else if (scaling > meta->scaling) {
+    value.integer = integer / (scaling / meta->scaling);
+  }
+  else {
+    value.integer = integer * (meta->scaling / scaling);
+  }
+
+  return oonf_layer2_data_set(l2data, origin, meta, &value);
+}
+
+/**
  * Compare two layer2 data objects
  * @param left left parameter for comparator
  * @param right right parameter for comparator
@@ -434,12 +467,16 @@ oonf_layer2_data_get_comparator_string(enum oonf_layer2_data_comparator_type typ
 }
 
 /**
- * @param type type index of layer2 data
+ * @param meta type index of layer2 metadata
  * @return the string name of a layer2 data type
  */
 const char *
-oonf_layer2_data_get_type_string(enum oonf_layer2_data_type type) {
-  return _data_types[type];
+oonf_layer2_data_get_type_string(const struct oonf_layer2_metadata *meta) {
+  static const char NONE[] = "NONE";
+  if (!meta) {
+    return NONE;
+  }
+  return _data_types[meta->type];
 }
 
 /**
@@ -450,6 +487,8 @@ oonf_layer2_data_get_type_string(enum oonf_layer2_data_type type) {
 struct oonf_layer2_net *
 oonf_layer2_net_add(const char *ifname) {
   struct oonf_layer2_net *l2net;
+  enum oonf_layer2_network_index netidx;
+  enum oonf_layer2_neighbor_index neighidx;
 
   if (!ifname) {
     return NULL;
@@ -481,6 +520,14 @@ oonf_layer2_net_add(const char *ifname) {
   l2net->if_listener.name = l2net->name;
   os_interface_add(&l2net->if_listener);
 
+  /* initialize data sections */
+  for (netidx=0; netidx<OONF_LAYER2_NET_COUNT; netidx++) {
+    l2net->data[netidx]._meta = oonf_layer2_net_metadata_get(netidx);
+  }
+  for (neighidx=0; neighidx<OONF_LAYER2_NEIGH_COUNT; neighidx++) {
+    l2net->neighdata[neighidx]._meta = oonf_layer2_neigh_metadata_get(neighidx);
+  }
+
   oonf_class_event(&_l2network_class, l2net, OONF_OBJECT_ADDED);
 
   return l2net;
@@ -773,6 +820,7 @@ oonf_layer2_neigh_generate_lid(struct oonf_layer2_neigh_key *key,
 struct oonf_layer2_neigh *
 oonf_layer2_neigh_add_lid(struct oonf_layer2_net *l2net, const struct oonf_layer2_neigh_key *key) {
   struct oonf_layer2_neigh *l2neigh;
+  enum oonf_layer2_neighbor_index neighidx;
 
   if (netaddr_get_address_family(&key->addr) != AF_MAC48 && netaddr_get_address_family(&key->addr) != AF_EUI64) {
     return NULL;
@@ -797,6 +845,11 @@ oonf_layer2_neigh_add_lid(struct oonf_layer2_net *l2net, const struct oonf_layer
   avl_init(&l2neigh->destinations, avl_comp_netaddr, false);
   avl_init(&l2neigh->remote_neighbor_ips, avl_comp_netaddr, false);
 
+  /* initialize metadata */
+  for (neighidx=0; neighidx<OONF_LAYER2_NEIGH_COUNT; neighidx++) {
+    l2neigh->data[neighidx]._meta = oonf_layer2_neigh_metadata_get(neighidx);
+  }
+
   oonf_class_event(&_l2neighbor_class, l2neigh, OONF_OBJECT_ADDED);
 
   return l2neigh;
index 3dde639..a4af355 100644 (file)
@@ -299,7 +299,7 @@ dlep_extension_radio_write_session_init_ack(
 
     if (!oonf_layer2_data_has_value(l2data)) {
       meta = oonf_layer2_neigh_metadata_get(neigh_idx);
-      oonf_layer2_data_set(l2data, session->l2_default_origin, meta->type, &ext->neigh_mapping[i].default_value);
+      oonf_layer2_data_set(l2data, session->l2_default_origin, meta, &ext->neigh_mapping[i].default_value);
     }
   }
 
@@ -314,7 +314,7 @@ dlep_extension_radio_write_session_init_ack(
 
     if (!oonf_layer2_data_has_value(l2data)) {
       meta = oonf_layer2_net_metadata_get(net_idx);
-      oonf_layer2_data_set(l2data, session->l2_default_origin, meta->type, &ext->if_mapping[i].default_value);
+      oonf_layer2_data_set(l2data, session->l2_default_origin, meta, &ext->if_mapping[i].default_value);
     }
   }
 
index 36cd196..fb152ac 100644 (file)
@@ -487,11 +487,12 @@ dlep_reader_status(enum dlep_status *status, char *text, size_t text_length, str
  * @param meta metadata description for data
  * @param session dlep session
  * @param dlep_tlv DLEP TLV id
+ * @param scaling fixed integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 int
 dlep_reader_map_identity(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv) {
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling) {
   struct dlep_parser_value *value;
   int64_t l2value;
   uint64_t tmp64;
@@ -527,10 +528,10 @@ dlep_reader_map_identity(struct oonf_layer2_data *data, const struct oonf_layer2
 
     switch (meta->type) {
       case OONF_LAYER2_INTEGER_DATA:
-        oonf_layer2_data_set_int64(data, session->l2_origin, l2value);
+        oonf_layer2_data_set_int64(data, session->l2_origin, meta, l2value, scaling);
         break;
       case OONF_LAYER2_BOOLEAN_DATA:
-        oonf_layer2_data_set_bool(data, session->l2_origin, l2value != 0);
+        oonf_layer2_data_set_bool(data, session->l2_origin, meta, l2value != 0);
         break;
       default:
         return -1;
@@ -550,14 +551,16 @@ dlep_reader_map_identity(struct oonf_layer2_data *data, const struct oonf_layer2
  *   (minus 1) of the conversion that failed.
  */
 int
-dlep_reader_map_l2neigh_data(struct oonf_layer2_data *data, struct dlep_session *session, struct dlep_extension *ext) {
+dlep_reader_map_l2neigh_data(struct oonf_layer2_data *data, struct dlep_session *session,
+    struct dlep_extension *ext) {
   struct dlep_neighbor_mapping *map;
   size_t i;
 
   for (i = 0; i < ext->neigh_mapping_count; i++) {
     map = &ext->neigh_mapping[i];
 
-    if (map->from_tlv(&data[map->layer2], oonf_layer2_neigh_metadata_get(map->layer2), session, map->dlep)) {
+    if (map->from_tlv(&data[map->layer2], oonf_layer2_neigh_metadata_get(map->layer2), session,
+        map->dlep, map->scaling)) {
       return -(i + 1);
     }
   }
@@ -582,7 +585,8 @@ dlep_reader_map_l2net_data(struct oonf_layer2_data *data, struct dlep_session *s
   for (i = 0; i < ext->if_mapping_count; i++) {
     map = &ext->if_mapping[i];
 
-    if (map->from_tlv(&data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), session, map->dlep)) {
+    if (map->from_tlv(&data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), session,
+        map->dlep, map->scaling)) {
       return -(i + 1);
     }
   }
index b88260b..1b93e16 100644 (file)
@@ -385,7 +385,7 @@ dlep_writer_add_supported_extensions(struct dlep_writer *writer, const uint16_t
  */
 int
 dlep_writer_map_identity(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length) {
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling) {
   int64_t l2value64;
   uint64_t tmp64;
   uint32_t tmp32;
@@ -404,7 +404,7 @@ dlep_writer_map_identity(struct dlep_writer *writer, struct oonf_layer2_data *da
 
   switch (oonf_layer2_data_get_type(data)) {
     case OONF_LAYER2_INTEGER_DATA:
-      l2value64 = oonf_layer2_data_get_int64(data, 0);
+      l2value64 = oonf_layer2_data_get_int64(data, scaling, 0);
       break;
     case OONF_LAYER2_BOOLEAN_DATA:
       l2value64 = oonf_layer2_data_get_boolean(data, false) ? 1 : 0;
@@ -464,7 +464,7 @@ dlep_writer_map_l2neigh_data(
       ptr = &def[map->layer2];
     }
 
-    if (map->to_tlv(writer, ptr, oonf_layer2_neigh_metadata_get(map->layer2), map->dlep, map->length)) {
+    if (map->to_tlv(writer, ptr, oonf_layer2_neigh_metadata_get(map->layer2), map->dlep, map->length, map->scaling)) {
       return -(i + 1);
     }
   }
@@ -489,7 +489,7 @@ dlep_writer_map_l2net_data(struct dlep_writer *writer, struct dlep_extension *ex
   for (i = 0; i < ext->if_mapping_count; i++) {
     map = &ext->if_mapping[i];
 
-    if (map->to_tlv(writer, &data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), map->dlep, map->length)) {
+    if (map->to_tlv(writer, &data[map->layer2], oonf_layer2_net_metadata_get(map->layer2), map->dlep, map->length, map->scaling)) {
       return -(i + 1);
     }
   }
index 9c3a335..fd2d7ca 100644 (file)
@@ -159,6 +159,7 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_MDRR_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_MAX_BITRATE,
     .length = 8,
+    .scaling = 1,
 
     .mandatory = true,
     .default_value.integer = 0,
@@ -170,6 +171,7 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_MDRT_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_MAX_BITRATE,
     .length = 8,
+    .scaling = 1,
 
     .mandatory = true,
     .default_value.integer = 0,
@@ -181,6 +183,7 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_CDRR_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_BITRATE,
     .length = 8,
+    .scaling = 1,
 
     .mandatory = true,
     .default_value.integer = 0,
@@ -192,6 +195,7 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_CDRT_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_BITRATE,
     .length = 8,
+    .scaling = 1,
 
     .mandatory = true,
     .default_value.integer = 0,
@@ -203,9 +207,10 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_LATENCY_TLV,
     .layer2 = OONF_LAYER2_NEIGH_LATENCY,
     .length = 8,
+    .scaling = 1000000,
 
     .mandatory = true,
-    .default_value.integer = 1,
+    .default_value.integer = 1000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -221,6 +226,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_RLQR_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_RLQ,
     .length = 1,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -228,6 +235,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_RLQT_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_RLQ,
     .length = 1,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
index 408b182..edf8d34 100644 (file)
@@ -341,6 +341,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_MDRR_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_MAX_BITRATE,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -348,6 +350,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_MDRT_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_MAX_BITRATE,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -362,6 +366,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_CDRT_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_BITRATE,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -369,6 +375,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_LATENCY_TLV,
     .layer2 = OONF_LAYER2_NEIGH_LATENCY,
     .length = 8,
+    .scaling = 1000000,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -376,6 +384,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_RESOURCES_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RESOURCES,
     .length = 1,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -383,6 +393,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_RLQR_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_RLQ,
     .length = 1,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
index 3cb8036..00d28f1 100644 (file)
 
 #include <oonf/generic/dlep/ext_l1_statistics/l1_statistics.h>
 
-static int _map_array(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv, enum oonf_layer2_network_index l2idx);
-static int _map_frequency(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv);
-static int _map_bandwidth(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv);
-
-static int dlep_writer_map_array(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, enum oonf_layer2_network_index l2idx);
-static int dlep_writer_map_frequency(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length);
-static int dlep_writer_map_bandwidth(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length);
+static int _reader_map_array (struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling, enum oonf_layer2_network_index l2idx);
+static int _reader_map_frequency (struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling);
+static int _reader_map_bandwidth (struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling);
+
+static int _writer_map_array (struct dlep_writer *writer, struct oonf_layer2_data *data,
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling,
+  enum oonf_layer2_network_index l2idx);
+static int _writer_map_frequency (struct dlep_writer *writer, struct oonf_layer2_data *data,
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling);
+static int _writer_map_bandwidth (struct dlep_writer *writer, struct oonf_layer2_data *data,
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling);
 
 /* peer initialization ack */
 static const uint16_t _session_initack_tlvs[] = {
@@ -163,6 +164,7 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_SIGNAL_RX_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_SIGNAL,
     .length = 4,
+    .scaling = 1000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -171,6 +173,7 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_SIGNAL_TX_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_SIGNAL,
     .length = 4,
+    .scaling = 1000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -182,26 +185,29 @@ static struct dlep_network_mapping _net_mappings[] = {
     .dlep = DLEP_FREQUENCY_TLV,
     .layer2 = OONF_LAYER2_NET_FREQUENCY_1,
     .length = 8,
+    .scaling = 1,
 
     .mandatory = true,
 
-    .from_tlv = _map_frequency,
-    .to_tlv = dlep_writer_map_frequency,
+    .from_tlv = _reader_map_frequency,
+    .to_tlv = _writer_map_frequency,
   },
   {
     .dlep = DLEP_BANDWIDTH_TLV,
     .layer2 = OONF_LAYER2_NET_BANDWIDTH_1,
     .length = 8,
+    .scaling = 1,
 
     .mandatory = true,
 
-    .from_tlv = _map_bandwidth,
-    .to_tlv = dlep_writer_map_bandwidth,
+    .from_tlv = _reader_map_bandwidth,
+    .to_tlv = _writer_map_bandwidth,
   },
   {
     .dlep = DLEP_NOISE_LEVEL_TLV,
     .layer2 = OONF_LAYER2_NET_NOISE,
     .length = 4,
+    .scaling = 1000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -210,6 +216,7 @@ static struct dlep_network_mapping _net_mappings[] = {
     .dlep = DLEP_CHANNEL_ACTIVE_TLV,
     .layer2 = OONF_LAYER2_NET_CHANNEL_ACTIVE,
     .length = 8,
+    .scaling = 1000000000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -218,6 +225,7 @@ static struct dlep_network_mapping _net_mappings[] = {
     .dlep = DLEP_CHANNEL_BUSY_TLV,
     .layer2 = OONF_LAYER2_NET_CHANNEL_BUSY,
     .length = 8,
+    .scaling = 1000000000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -226,6 +234,7 @@ static struct dlep_network_mapping _net_mappings[] = {
     .dlep = DLEP_CHANNEL_RX_TLV,
     .layer2 = OONF_LAYER2_NET_CHANNEL_RX,
     .length = 8,
+    .scaling = 1000000000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -234,6 +243,7 @@ static struct dlep_network_mapping _net_mappings[] = {
     .dlep = DLEP_CHANNEL_TX_TLV,
     .layer2 = OONF_LAYER2_NET_CHANNEL_TX,
     .length = 8,
+    .scaling = 1000000000,
 
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
@@ -271,12 +281,13 @@ dlep_l1_statistics_init(void) {
  * @param data layer2 data object
  * @param session dlep session
  * @param dlep_tlv dlep tlv
+ * @param scaling fixed integer arithmetics scaling factor
  * @param l2idx layer2 index
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-_map_array(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta __attribute__((unused)),
-  struct dlep_session *session, uint16_t dlep_tlv, enum oonf_layer2_network_index l2idx) {
+_reader_map_array (struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling, enum oonf_layer2_network_index l2idx) {
   struct dlep_parser_value *value;
   int64_t l2value;
   const uint8_t *dlepvalue;
@@ -303,7 +314,7 @@ _map_array(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *met
 
   /* copy into signed integer and set to l2 value */
   memcpy(&l2value, &tmp64[0], 8);
-  oonf_layer2_data_set_int64(data, session->l2_origin, l2value);
+  oonf_layer2_data_set_int64(data, session->l2_origin, meta, l2value, scaling);
 
   if (value->length == 16) {
     switch (l2idx) {
@@ -318,7 +329,7 @@ _map_array(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *met
     }
 
     memcpy(&l2value, &tmp64[1], 8);
-    oonf_layer2_data_set_int64(data, session->l2_origin, l2value);
+    oonf_layer2_data_set_int64(data, session->l2_origin, meta, l2value, scaling);
   }
   return 0;
 }
@@ -329,12 +340,13 @@ _map_array(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *met
  * @param meta metadata description for data
  * @param session dlep session
  * @param dlep_tlv dlep TLV id
+ * @param scaling fixed integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-_map_frequency(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv) {
-  return _map_array(data, meta, session, dlep_tlv, OONF_LAYER2_NET_FREQUENCY_1);
+_reader_map_frequency (struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling) {
+  return _reader_map_array (data, meta, session, dlep_tlv, scaling, OONF_LAYER2_NET_FREQUENCY_1);
 }
 
 /**
@@ -343,12 +355,13 @@ _map_frequency(struct oonf_layer2_data *data, const struct oonf_layer2_metadata
  * @param meta metadata description for data
  * @param session dlep session
  * @param dlep_tlv dlep TLV id
+ * @param scaling fixed integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-_map_bandwidth(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
-  struct dlep_session *session, uint16_t dlep_tlv) {
-  return _map_array(data, meta, session, dlep_tlv, OONF_LAYER2_NET_BANDWIDTH_1);
+_reader_map_bandwidth (struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta,
+  struct dlep_session *session, uint16_t dlep_tlv, uint64_t scaling) {
+  return _reader_map_array (data, meta, session, dlep_tlv, scaling, OONF_LAYER2_NET_BANDWIDTH_1);
 }
 
 /**
@@ -358,12 +371,14 @@ _map_bandwidth(struct oonf_layer2_data *data, const struct oonf_layer2_metadata
  * @param data layer2 network data
  * @param tlv dlep tlv id
  * @param length tlv length
+ * @param scaling fixed integer arithmetics scaling factor
  * @param l2idx layer2 network index
  * @return -1 if an error happened, 0 otherwise
  */
 int
-dlep_writer_map_array(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, enum oonf_layer2_network_index l2idx) {
+_writer_map_array (struct dlep_writer *writer, struct oonf_layer2_data *data,
+    const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling,
+    enum oonf_layer2_network_index l2idx) {
   struct oonf_layer2_data *data2;
   int64_t l2value;
   uint64_t tmp64[2];
@@ -387,14 +402,14 @@ dlep_writer_map_array(struct dlep_writer *writer, struct oonf_layer2_data *data,
         return -1;
     }
 
-    if (!oonf_layer2_data_read_int64(&l2value, data2)) {
+    if (!oonf_layer2_data_read_int64(&l2value, data2, scaling)) {
       memcpy(&tmp64[1], &l2value, 8);
       tmp64[1] = htobe64(tmp64[1]);
       length = 16;
     }
   }
 
-  l2value = oonf_layer2_data_get_int64(data, 0);
+  l2value = oonf_layer2_data_get_int64(data, scaling, 0);
   memcpy(&tmp64[0], &l2value, 8);
   tmp64[0] = htobe64(tmp64[0]);
 
@@ -408,12 +423,13 @@ dlep_writer_map_array(struct dlep_writer *writer, struct oonf_layer2_data *data,
  * @param data layer2 network data array
  * @param tlv DLEP tlv id
  * @param length tlv length
+ * @param scaling fixed integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-dlep_writer_map_frequency(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length) {
-  return dlep_writer_map_array(writer, data, meta, tlv, length, OONF_LAYER2_NET_FREQUENCY_1);
+_writer_map_frequency (struct dlep_writer *writer, struct oonf_layer2_data *data,
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling) {
+  return _writer_map_array (writer, data, meta, tlv, length, scaling, OONF_LAYER2_NET_FREQUENCY_1);
 }
 
 /**
@@ -422,10 +438,11 @@ dlep_writer_map_frequency(struct dlep_writer *writer, struct oonf_layer2_data *d
  * @param data layer2 network data array
  * @param tlv DLEP tlv id
  * @param length tlv length
+ * @param scaling fixed integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 static int
-dlep_writer_map_bandwidth(struct dlep_writer *writer, struct oonf_layer2_data *data,
-  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length) {
-  return dlep_writer_map_array(writer, data, meta, tlv, length, OONF_LAYER2_NET_BANDWIDTH_1);
+_writer_map_bandwidth (struct dlep_writer *writer, struct oonf_layer2_data *data,
+  const struct oonf_layer2_metadata *meta, uint16_t tlv, uint16_t length, uint64_t scaling) {
+  return _writer_map_array (writer, data, meta, tlv, length, scaling, OONF_LAYER2_NET_BANDWIDTH_1);
 }
index a3d7d56..250476d 100644 (file)
@@ -146,6 +146,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_FRAMES_R_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_FRAMES,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -153,6 +155,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_FRAMES_T_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_FRAMES,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -160,6 +164,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_FRAMES_RETRIES_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_RETRIES,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -167,6 +173,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_FRAMES_FAILED_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_FAILED,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -174,6 +182,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_BYTES_R_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_BYTES,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -181,6 +191,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_BYTES_T_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_BYTES,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -188,6 +200,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_THROUGHPUT_T_TLV,
     .layer2 = OONF_LAYER2_NEIGH_TX_THROUGHPUT,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
@@ -195,6 +209,8 @@ static struct dlep_neighbor_mapping _neigh_mappings[] = {
     .dlep = DLEP_CDRR_BC_TLV,
     .layer2 = OONF_LAYER2_NEIGH_RX_BC_BITRATE,
     .length = 8,
+    .scaling = 1,
+
     .from_tlv = dlep_reader_map_identity,
     .to_tlv = dlep_writer_map_identity,
   },
index 490cb0a..e6c89f8 100644 (file)
@@ -89,7 +89,7 @@ static struct oonf_layer2_origin _l2_origin = {
 static struct oonf_layer2_origin _l2_default_origin = {
   .name = "dlep radio defaults",
   .proactive = false,
-  .priority = OONF_LAYER2_ORIGIN_UNRELIABLE,
+  .priority = OONF_LAYER2_ORIGIN_DEFAULT,
 };
 
 /**
index 6348960..fd36c63 100644 (file)
@@ -223,8 +223,8 @@ _cb_transmission_event(struct oonf_timer_instance *ptr __attribute((unused))) {
     OONF_DEBUG(LOG_ETH, "Set default link speed of interface %s to %s", os_if->name,
       isonumber_from_s64(&ibuf, ethspeed, "bit/s", 0, false));
 
-    oonf_layer2_data_set_int64(&l2net->neighdata[OONF_LAYER2_NEIGH_RX_BITRATE], &_l2_origin, ethspeed);
-    oonf_layer2_data_set_int64(&l2net->neighdata[OONF_LAYER2_NEIGH_TX_BITRATE], &_l2_origin, ethspeed);
+    oonf_layer2_data_set_int64(&l2net->neighdata[OONF_LAYER2_NEIGH_RX_BITRATE], &_l2_origin, NULL, ethspeed, 1);
+    oonf_layer2_data_set_int64(&l2net->neighdata[OONF_LAYER2_NEIGH_TX_BITRATE], &_l2_origin, NULL, ethspeed, 1);
   }
 }
 
index 46b3fa0..eeeddb2 100644 (file)
@@ -87,6 +87,7 @@ struct l2_config_data {
   enum oonf_layer2_data_type data_type;
   union oonf_layer2_value data;
   char txt_value[_MAX_L2_VALUE_LEN];
+  bool overwrite;
 };
 
 /* all configuration options for an interface */
@@ -127,35 +128,42 @@ static void _cb_config_changed(void);
 static struct cfg_schema_entry _l2net_entries[] = {
   CFG_MAP_CHOICE_L2NET(l2_config_data, data_idx, "l2net_key", "", "Layer2 network key for configuration"),
   CFG_MAP_STRING_ARRAY(l2_config_data, txt_value, "l2net_value", "", "Layer2 network value", _MAX_L2_VALUE_LEN),
+  CFG_MAP_BOOL(l2_config_data, overwrite, "l2net_overwrite", "false", "Layer2 overwrite priority"),
 };
 static struct cfg_schema_entry _l2net_def_entries[] = {
   CFG_MAP_CHOICE_L2NEIGH(l2_config_data, data_idx, "l2neigh_key", "", "Layer2 neighbor key for configuration"),
   CFG_MAP_STRING_ARRAY(
     l2_config_data, txt_value, "l2neigh_value", "", "Layer2 neighbor value for default neighbor data", _MAX_L2_VALUE_LEN),
+  CFG_MAP_BOOL(l2_config_data, overwrite, "l2net_overwrite", "false", "Layer2 overwrite priority"),
 };
 static struct cfg_schema_entry _l2neigh_entries[] = {
   CFG_MAP_CHOICE_L2NEIGH(l2_config_data, data_idx, "l2neigh_key", "", "Layer2 neighbor key for configuration"),
   CFG_MAP_STRING_ARRAY(l2_config_data, txt_value, "l2neigh_value", "", "Layer2 neighbor value", _MAX_L2_VALUE_LEN),
   CFG_MAP_NETADDR_MAC48(l2_config_data, mac, "l2neigh_mac", "", "MAC address of neighbor", false, false),
+  CFG_MAP_BOOL(l2_config_data, overwrite, "l2net_overwrite", "false", "Layer2 overwrite priority"),
 };
 static struct cfg_schema_entry _l2neigh_ip_entries[] = {
   CFG_MAP_NETADDR_MAC48(l2_config_data, mac, "l2neigh_mac", "", "MAC address of neighbor", false, false),
   CFG_MAP_NETADDR_V46(l2_config_data, data.addr, "l2neigh_ip", "", "IP address to neighbor", false, false),
+  CFG_MAP_BOOL(l2_config_data, overwrite, "l2net_overwrite", "false", "Layer2 overwrite priority"),
 };
 static struct cfg_schema_entry _l2neigh_dst_entries[] = {
   CFG_MAP_NETADDR_MAC48(l2_config_data, mac, "l2neigh_mac", "", "MAC address of neighbor", false, false),
   CFG_MAP_NETADDR_MAC48(
     l2_config_data, data.addr, "l2neigh_dst", "", "Secondary MAC address of neighbor", false, false),
+  CFG_MAP_BOOL(l2_config_data, overwrite, "l2net_overwrite", "false", "Layer2 overwrite priority"),
 };
 
 static struct cfg_schema_token_customizer _if_value_customizer = {
   .cb_validator = _cb_if_value_validator,
   .cb_tobin = _cb_if_value_tobin,
+  .optional = 1,
 };
 
 static struct cfg_schema_token_customizer _neigh_value_customizer = {
   .cb_validator = _cb_neigh_value_validator,
   .cb_tobin = _cb_neigh_value_tobin,
+  .optional = 1,
 };
 
 static struct cfg_schema_entry _l2_config_if_entries[] = {
@@ -208,13 +216,17 @@ static struct oonf_subsystem _oonf_layer2_config_subsystem = {
 DECLARE_OONF_PLUGIN(_oonf_layer2_config_subsystem);
 
 /* originator for smooth set/remove of configured layer2 values */
-static struct oonf_layer2_origin _l2_origin_current = {
+static struct oonf_layer2_origin _l2_origin_current_configured = {
   .name = "layer2 config",
   .priority = OONF_LAYER2_ORIGIN_CONFIGURED,
 };
+static struct oonf_layer2_origin _l2_origin_current_overwrite = {
+  .name = "layer2 config overwrite",
+  .priority = OONF_LAYER2_ORIGIN_OVERWRITE,
+};
 static struct oonf_layer2_origin _l2_origin_old = {
   .name = "layer2 config old",
-  .priority = OONF_LAYER2_ORIGIN_CONFIGURED,
+  .priority = OONF_LAYER2_ORIGIN_UNKNOWN,
 };
 
 /* listener for removal of layer2 data */
@@ -248,7 +260,8 @@ static struct oonf_timer_class _reconfigure_timer = {
  */
 static int
 _init(void) {
-  oonf_layer2_origin_add(&_l2_origin_current);
+  oonf_layer2_origin_add(&_l2_origin_current_configured);
+  oonf_layer2_origin_add(&_l2_origin_current_overwrite);
   oonf_layer2_origin_add(&_l2_origin_old);
 
   oonf_class_extension_add(&_l2net_listener);
@@ -275,7 +288,8 @@ _cleanup(void) {
   oonf_class_extension_remove(&_l2net_listener);
   oonf_class_extension_remove(&_l2neigh_listener);
 
-  oonf_layer2_origin_remove(&_l2_origin_current);
+  oonf_layer2_origin_remove(&_l2_origin_current_overwrite);
+  oonf_layer2_origin_remove(&_l2_origin_current_configured);
   oonf_layer2_origin_remove(&_l2_origin_old);
 }
 
@@ -355,7 +369,7 @@ _cb_if_value_validator(struct autobuf *out, const char *section_name, const char
     cfg_append_printable_line(out,
       "Value '%s' for entry '%s' in section %s does not use the data"
       " type %s for layer2 network key %s",
-      value, entry_name, section_name, oonf_layer2_data_get_type_string(meta->type), meta->key);
+      value, entry_name, section_name, oonf_layer2_data_get_type_string(meta), meta->key);
   }
   return 0;
 }
@@ -411,7 +425,7 @@ _cb_neigh_value_validator(struct autobuf *out, const char *section_name, const c
     cfg_append_printable_line(out,
       "Value '%s' for entry '%s' in section %s does not use the data"
       " type %s for layer2 neighbor key %s",
-      value, entry_name, section_name, oonf_layer2_data_get_type_string(meta->type), meta->key);
+      value, entry_name, section_name, oonf_layer2_data_get_type_string(meta), meta->key);
   }
   return 0;
 }
@@ -498,6 +512,7 @@ _configure_if_data(struct l2_config_if_data *if_data) {
   struct oonf_layer2_net *l2net;
   struct l2_config_data *entry;
   struct oonf_layer2_neigh_key key;
+  struct oonf_layer2_origin *origin;
   size_t i;
 
   l2net = oonf_layer2_net_get(if_data->interf);
@@ -510,39 +525,44 @@ _configure_if_data(struct l2_config_if_data *if_data) {
 
   /* relabel old entries */
   if (l2net) {
-    oonf_layer2_net_relabel(l2net, &_l2_origin_old, &_l2_origin_current);
+    oonf_layer2_net_relabel(l2net, &_l2_origin_old, &_l2_origin_current_configured);
+    oonf_layer2_net_relabel(l2net, &_l2_origin_old, &_l2_origin_current_overwrite);
 
     for (i = 0; i < if_data->count; i++) {
       entry = &if_data->d[i];
 
+      origin = entry->overwrite ? &_l2_origin_current_overwrite : &_l2_origin_current_configured;
       switch (entry->config_type) {
         case L2_NET:
-          oonf_layer2_data_set(&l2net->data[entry->data_idx], &_l2_origin_current, entry->data_type, &entry->data);
+          oonf_layer2_data_set(&l2net->data[entry->data_idx], origin,
+                               oonf_layer2_net_metadata_get(entry->data_idx), &entry->data);
           break;
         case L2_NET_IP:
-          oonf_layer2_net_add_ip(l2net, &_l2_origin_current, &entry->data.addr);
+          oonf_layer2_net_add_ip(l2net, origin, &entry->data.addr);
           break;
         case L2_DEF:
-          oonf_layer2_data_set(&l2net->neighdata[entry->data_idx], &_l2_origin_current, entry->data_type, &entry->data);
+          oonf_layer2_data_set(&l2net->neighdata[entry->data_idx], origin,
+                               oonf_layer2_neigh_metadata_get(entry->data_idx), &entry->data);
           break;
         case L2_NEIGH:
           memset(&key, 0, sizeof(key));
           memcpy(&key.addr, &entry->mac, sizeof(key.addr));
           l2neigh = oonf_layer2_neigh_add_lid(l2net, &key);
           if (l2neigh) {
-            oonf_layer2_data_set(&l2neigh->data[entry->data_idx], &_l2_origin_current, entry->data_type, &entry->data);
+            oonf_layer2_data_set(&l2neigh->data[entry->data_idx], origin,
+                                 oonf_layer2_neigh_metadata_get(entry->data_idx), &entry->data);
           }
           break;
         case L2_NEIGH_IP:
           l2neigh = oonf_layer2_neigh_add(l2net, &entry->mac);
           if (l2neigh) {
-            oonf_layer2_neigh_add_ip(l2neigh, &_l2_origin_current, &entry->data.addr);
+            oonf_layer2_neigh_add_ip(l2neigh, origin, &entry->data.addr);
           }
           break;
         case L2_DST:
           l2neigh = oonf_layer2_neigh_add(l2net, &entry->mac);
           if (l2neigh) {
-            oonf_layer2_destination_add(l2neigh, &entry->data.addr, &_l2_origin_current);
+            oonf_layer2_destination_add(l2neigh, &entry->data.addr, origin);
           }
           break;
         default:
index 1b1b982..45f94ab 100644 (file)
@@ -173,13 +173,13 @@ _cleanup(void) {
 }
 
 static void
-_set_data(struct oonf_layer2_data *data, enum oonf_layer2_data_type type, int64_t value) {
-  switch (type) {
+_set_data(struct oonf_layer2_data *data, const struct oonf_layer2_metadata *meta, int64_t value) {
+  switch (meta->type) {
     case OONF_LAYER2_INTEGER_DATA:
-      oonf_layer2_data_set_int64(data, &_origin, value);
+      oonf_layer2_data_set_int64(data, &_origin, meta, value, meta->scaling);
       break;
     case OONF_LAYER2_BOOLEAN_DATA:
-      oonf_layer2_data_set_bool(data, &_origin, (value & 1) != 0);
+      oonf_layer2_data_set_bool(data, &_origin, meta, (value & 1) != 0);
       break;
     default:
       break;
@@ -221,10 +221,10 @@ _cb_l2gen_event(struct oonf_timer_instance *ptr __attribute((unused))) {
   net->last_seen = oonf_clock_getNow();
 
   for (net_idx = 0; net_idx < OONF_LAYER2_NET_COUNT; net_idx++) {
-    _set_data(&net->data[net_idx], oonf_layer2_net_metadata_get(net_idx)->type, event_counter);
+    _set_data(&net->data[net_idx], oonf_layer2_net_metadata_get(net_idx), event_counter);
   }
   for (neigh_idx = 0; neigh_idx < OONF_LAYER2_NEIGH_COUNT; neigh_idx++) {
-    _set_data(&net->neighdata[neigh_idx], oonf_layer2_neigh_metadata_get(neigh_idx)->type, event_counter);
+    _set_data(&net->neighdata[neigh_idx], oonf_layer2_neigh_metadata_get(neigh_idx), event_counter);
   }
 
   if (oonf_layer2_net_commit(net)) {
@@ -248,7 +248,7 @@ _cb_l2gen_event(struct oonf_timer_instance *ptr __attribute((unused))) {
   oonf_layer2_neigh_set_lastseen(neigh, oonf_clock_getNow());
 
   for (neigh_idx = 0; neigh_idx < OONF_LAYER2_NEIGH_COUNT; neigh_idx++) {
-    _set_data(&neigh->data[neigh_idx], oonf_layer2_neigh_metadata_get(neigh_idx)->type, event_counter);
+    _set_data(&neigh->data[neigh_idx], oonf_layer2_neigh_metadata_get(neigh_idx), event_counter);
   }
   oonf_layer2_neigh_commit(neigh);
 }
index 068bf38..6f7d784 100644 (file)
@@ -249,7 +249,7 @@ _cb_validate_linkdata(
   /* test if first word is a human readable number */
   ptr = str_cpynextword(sbuf.buf, value, sizeof(sbuf));
   if (cfg_validate_int(out, section_name, entry->key.entry, sbuf.buf, INT64_MIN, INT64_MAX, 8,
-        oonf_layer2_neigh_metadata_get(idx)->fraction)) {
+        oonf_layer2_neigh_metadata_get(idx)->scaling)) {
     return -1;
   }
 
@@ -274,6 +274,7 @@ _cb_validate_linkdata(
  */
 static void
 _parse_strarray(struct strarray *array, const char *ifname, enum oonf_layer2_neighbor_index idx) {
+  const struct oonf_layer2_metadata *meta;
   struct oonf_layer2_neigh *l2neigh;
   struct oonf_layer2_net *l2net;
   struct netaddr_str nbuf;
@@ -288,16 +289,18 @@ _parse_strarray(struct strarray *array, const char *ifname, enum oonf_layer2_nei
     return;
   }
 
+  meta = oonf_layer2_neigh_metadata_get(idx);
+
   strarray_for_each_element(array, entry) {
     ptr = str_cpynextword(hbuf.buf, entry, sizeof(hbuf));
-    if (isonumber_to_s64(&value, hbuf.buf, oonf_layer2_neigh_metadata_get(idx)->fraction)) {
+    if (isonumber_to_s64(&value, hbuf.buf, meta->scaling)) {
       continue;
     }
 
     if (ptr == NULL) {
       /* add network wide data entry */
-      if (!oonf_layer2_data_set_int64(&l2net->neighdata[idx], &_l2_origin_current, value)) {
-        OONF_INFO(LOG_LINK_CONFIG, "if-wide %s for %s: %s", oonf_layer2_neigh_metadata_get(idx)->key, ifname, hbuf.buf);
+      if (!oonf_layer2_data_set_int64(&l2net->neighdata[idx], &_l2_origin_current, meta, value, meta->scaling)) {
+        OONF_INFO(LOG_LINK_CONFIG, "if-wide %s for %s: %s", meta->key, ifname, hbuf.buf);
       }
       continue;
     }
@@ -314,8 +317,8 @@ _parse_strarray(struct strarray *array, const char *ifname, enum oonf_layer2_nei
         continue;
       }
 
-      if (!oonf_layer2_data_set_int64(&l2neigh->data[idx], &_l2_origin_current, value)) {
-        OONF_INFO(LOG_LINK_CONFIG, "%s to neighbor %s on %s: %s", oonf_layer2_neigh_metadata_get(idx)->key, nbuf.buf,
+      if (!oonf_layer2_data_set_int64(&l2neigh->data[idx], &_l2_origin_current, meta, value, meta->scaling)) {
+        OONF_INFO(LOG_LINK_CONFIG, "%s to neighbor %s on %s: %s", meta->key, nbuf.buf,
           ifname, hbuf.buf);
       }
     }
index b3c1c82..ef0df7e 100644 (file)
@@ -168,10 +168,10 @@ nl80211_process_get_interface_result(struct nl80211_if *interf, struct nlmsghdr
     freq[0] *= 1000000ull;
     freq[1] *= 1000000ull;
 
-    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_FREQUENCY_1, freq[0]);
-    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_FREQUENCY_2, freq[1]);
-    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_BANDWIDTH_1, bandwidth[0]);
-    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_BANDWIDTH_2, bandwidth[1]);
+    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_FREQUENCY_1, freq[0], 1);
+    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_FREQUENCY_2, freq[1], 1);
+    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_BANDWIDTH_1, bandwidth[0], 1);
+    interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_BANDWIDTH_2, bandwidth[1], 1);
 
     if (bandwidth[0] > 0 && nl80211_create_broadcast_neighbor()) {
       /* calculate multicast rate */
@@ -179,7 +179,7 @@ nl80211_process_get_interface_result(struct nl80211_if *interf, struct nlmsghdr
 
       l2neigh = oonf_layer2_neigh_add(interf->l2net, &NETADDR_MAC48_BROADCAST);
       if (l2neigh) {
-        nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BITRATE, mc_rate);
+        nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BITRATE, mc_rate, 1);
       }
     }
   }
index c0858e1..fd75871 100644 (file)
@@ -174,10 +174,10 @@ nl80211_process_get_station_dump_result(struct nl80211_if *interf, struct nlmsgh
 
   /* byte data is 64 bit */
   if (sinfo[NL80211_STA_INFO_RX_BYTES64]) {
-    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_RX_BYTES, nla_get_u64(sinfo[NL80211_STA_INFO_RX_BYTES64]));
+    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_RX_BYTES, nla_get_u64(sinfo[NL80211_STA_INFO_RX_BYTES64]),1 );
   }
   if (sinfo[NL80211_STA_INFO_TX_BYTES64]) {
-    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BYTES, nla_get_u64(sinfo[NL80211_STA_INFO_TX_BYTES64]));
+    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BYTES, nla_get_u64(sinfo[NL80211_STA_INFO_TX_BYTES64]), 1);
   }
 
   /* packet data is only 32 bit */
@@ -198,13 +198,13 @@ nl80211_process_get_station_dump_result(struct nl80211_if *interf, struct nlmsgh
   if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
     int64_t rate = _get_bitrate(sinfo[NL80211_STA_INFO_TX_BITRATE]);
     if (rate) {
-      nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BITRATE, rate);
+      nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_BITRATE, rate, 1);
     }
   }
   if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
     int64_t rate = _get_bitrate(sinfo[NL80211_STA_INFO_RX_BITRATE]);
     if (rate) {
-      nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_RX_BITRATE, rate);
+      nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_RX_BITRATE, rate, 1);
     }
   }
 
@@ -215,7 +215,7 @@ nl80211_process_get_station_dump_result(struct nl80211_if *interf, struct nlmsgh
     rate = nla_get_u32(sinfo[NL80211_STA_INFO_EXPECTED_THROUGHPUT]);
 
     /* convert in bps */
-    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_THROUGHPUT, rate * 1024ll);
+    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_TX_THROUGHPUT, rate * 1024ll, 1);
   }
 
   /* signal strength is special too */
@@ -223,7 +223,7 @@ nl80211_process_get_station_dump_result(struct nl80211_if *interf, struct nlmsgh
     int8_t signal;
 
     signal = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
-    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_RX_SIGNAL, signal * 1000ll);
+    nl80211_change_l2neigh_data(l2neigh, OONF_LAYER2_NEIGH_RX_SIGNAL, signal, 1);
   }
 
   /* remove old data */
@@ -244,7 +244,7 @@ _handle_traffic(struct oonf_layer2_neigh *l2neigh, enum oonf_layer2_neighbor_ind
   old_value = 0;
 
   data = &l2neigh->data[idx];
-  oonf_layer2_data_read_int64(&old_value, data);
+  oonf_layer2_data_read_int64(&old_value, data, 0);
 
   new_value = old_value & UPPER_32_MASK;
   new_value |= (new_32bit & LOWER_32_MASK);
@@ -257,7 +257,7 @@ _handle_traffic(struct oonf_layer2_neigh *l2neigh, enum oonf_layer2_neighbor_ind
     OONF_DEBUG(LOG_NL80211, "Overflow, new: %016" PRIx64, new_value);
   }
 
-  return nl80211_change_l2neigh_data(l2neigh, idx, new_value);
+  return nl80211_change_l2neigh_data(l2neigh, idx, new_value, 1);
 }
 
 static int64_t
index 6b4369a..58eb3c4 100644 (file)
@@ -146,16 +146,16 @@ nl80211_process_get_survey_result(struct nl80211_if *interf, struct nlmsghdr *hd
 
   if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
     interf->ifdata_changed |= nl80211_change_l2net_data(
-      interf->l2net, OONF_LAYER2_NET_NOISE, 1000ll * (int8_t)nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]));
+      interf->l2net, OONF_LAYER2_NET_NOISE, (int8_t)nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]), 1);
   }
 
   if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_CHANNEL_ACTIVE,
-      1000000ll * (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]));
+      (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]), 1000);
   }
   if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_CHANNEL_BUSY,
-      1000000ll * (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]));
+      (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]), 1000);
   }
 #if 0
   /* I have no clue what this is */
@@ -167,10 +167,10 @@ nl80211_process_get_survey_result(struct nl80211_if *interf, struct nlmsghdr *hd
 #endif
   if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_CHANNEL_RX,
-      1000000ll * (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]));
+      (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]), 1000);
   }
   if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
     interf->ifdata_changed |= nl80211_change_l2net_data(interf->l2net, OONF_LAYER2_NET_CHANNEL_TX,
-      1000000ll * (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]));
+      (int64_t)nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]), 1000);
   }
 }
index 3b64b6d..c8e16f5 100644 (file)
@@ -358,12 +358,12 @@ nl80211_finalize_get_wiphy(struct nl80211_if *interf) {
   if (interf->max_rx) {
     OONF_DEBUG(LOG_NL80211, "Maximum rx rate for %s: %" PRId64, interf->name, interf->max_rx);
     interf->ifdata_changed |=
-      nl80211_change_l2net_neighbor_default(interf->l2net, OONF_LAYER2_NEIGH_RX_MAX_BITRATE, interf->max_rx);
+      nl80211_change_l2net_neighbor_default(interf->l2net, OONF_LAYER2_NEIGH_RX_MAX_BITRATE, interf->max_rx, 1);
   }
   if (interf->max_tx) {
     OONF_DEBUG(LOG_NL80211, "Maximum tx rate for %s: %" PRId64, interf->name, interf->max_tx);
     interf->ifdata_changed |=
-      nl80211_change_l2net_neighbor_default(interf->l2net, OONF_LAYER2_NEIGH_TX_MAX_BITRATE, interf->max_tx);
+      nl80211_change_l2net_neighbor_default(interf->l2net, OONF_LAYER2_NEIGH_TX_MAX_BITRATE, interf->max_tx, 1);
   }
 }
 
@@ -390,10 +390,10 @@ _get_max_bitrate(struct nl80211_if *interf, uint8_t *mcs, bool ht20_sgi, bool ht
     /* we don't know the bandwidth of the channel */
     return 0;
   }
-  bandwidth = oonf_layer2_data_get_int64(data, 0);
+  bandwidth = oonf_layer2_data_get_int64(data, 1, 0);
 
   data = &interf->l2net->data[OONF_LAYER2_NET_BANDWIDTH_2];
-  bandwidth += oonf_layer2_data_get_int64(data, 0);
+  bandwidth += oonf_layer2_data_get_int64(data, 1, 0);
 
   if (bandwidth == 20000000) {
     /* is 20 MHz */
index bc62de2..eb1995c 100644 (file)
@@ -385,11 +385,14 @@ nl80211_add_dst(struct oonf_layer2_neigh *l2neigh, const struct netaddr *dstmac)
  * @param l2net pointer to layer2 network
  * @param idx index of setting
  * @param value new value
+ * @param scaling fixpoint integer arithmetics scaling
  * @return true if value changed, false otherwise
  */
 bool
-nl80211_change_l2net_data(struct oonf_layer2_net *l2net, enum oonf_layer2_network_index idx, uint64_t value) {
-  return oonf_layer2_data_set_int64(&l2net->data[idx], &_layer2_updated_origin, value);
+nl80211_change_l2net_data(struct oonf_layer2_net *l2net, enum oonf_layer2_network_index idx,
+    int64_t value, int64_t scaling) {
+  return oonf_layer2_data_set_int64(&l2net->data[idx], &_layer2_updated_origin,
+      oonf_layer2_net_metadata_get(idx), value, scaling);
 }
 
 /**
@@ -401,8 +404,9 @@ nl80211_change_l2net_data(struct oonf_layer2_net *l2net, enum oonf_layer2_networ
  */
 bool
 nl80211_change_l2net_neighbor_default(
-  struct oonf_layer2_net *l2net, enum oonf_layer2_neighbor_index idx, uint64_t value) {
-  return oonf_layer2_data_set_int64(&l2net->neighdata[idx], &_layer2_updated_origin, value);
+  struct oonf_layer2_net *l2net, enum oonf_layer2_neighbor_index idx, int64_t value, int64_t scaling) {
+  return oonf_layer2_data_set_int64(&l2net->neighdata[idx], &_layer2_updated_origin,
+      oonf_layer2_neigh_metadata_get(idx), value, scaling);
 }
 
 /**
@@ -423,8 +427,10 @@ nl80211_cleanup_l2neigh_data(struct oonf_layer2_neigh *l2neigh) {
  * @return true if value changed, false otherwise
  */
 bool
-nl80211_change_l2neigh_data(struct oonf_layer2_neigh *l2neigh, enum oonf_layer2_neighbor_index idx, uint64_t value) {
-  return oonf_layer2_data_set_int64(&l2neigh->data[idx], &_layer2_updated_origin, value);
+nl80211_change_l2neigh_data(struct oonf_layer2_neigh *l2neigh, enum oonf_layer2_neighbor_index idx,
+    int64_t value, int64_t scaling) {
+  return oonf_layer2_data_set_int64(&l2neigh->data[idx], &_layer2_updated_origin,
+      oonf_layer2_neigh_metadata_get(idx), value, scaling);
 }
 
 /**
@@ -615,7 +621,7 @@ _get_next_query(void) {
       if (_current_query_if->ifdata_changed) {
         /* set fixed flags for nl80211 data */
         oonf_layer2_data_set_bool(
-          &_current_query_if->l2net->data[OONF_LAYER2_NET_MCS_BY_PROBING], &_layer2_updated_origin, true);
+          &_current_query_if->l2net->data[OONF_LAYER2_NET_MCS_BY_PROBING], &_layer2_updated_origin, NULL, true);
 
         /* cleanup old data and relable new one, then commit everything */
         oonf_layer2_net_cleanup(_current_query_if->l2net, &_layer2_data_origin, true);
index 7b96856..91c2a6d 100644 (file)
@@ -51,7 +51,7 @@
 #include <oonf/libcommon/string.h>
 
 static const char *_isonumber_u64_to_string(
-  char *out, size_t out_len, uint64_t number, const char *unit, size_t fraction, bool raw);
+  char *out, size_t out_len, uint64_t number, const char *unit, uint64_t scaling, bool raw);
 
 /**
  * Converts an unsigned 64 bit integer into a human readable number
@@ -62,14 +62,14 @@ static const char *_isonumber_u64_to_string(
  * @param out pointer to output buffer
  * @param number number to convert.
  * @param unit unit to be appended at the end, can be NULL
- * @param fraction number of fractional digits
+ * @param scaling fixed point integer arithmetics scaling factor
  * @param raw true if the whole text conversion should be bypassed
  *   and only the raw number shall be written, false otherwise
  * @return pointer to converted string
  */
 const char *
-isonumber_from_u64(struct isonumber_str *out, uint64_t number, const char *unit, int fraction, bool raw) {
-  return _isonumber_u64_to_string(out->buf, sizeof(*out), number, unit, fraction, raw);
+isonumber_from_u64(struct isonumber_str *out, uint64_t number, const char *unit, uint64_t scaling, bool raw) {
+  return _isonumber_u64_to_string(out->buf, sizeof(*out), number, unit, scaling, raw);
 }
 
 /**
@@ -81,13 +81,13 @@ isonumber_from_u64(struct isonumber_str *out, uint64_t number, const char *unit,
  * @param out pointer to output buffer
  * @param number number to convert.
  * @param unit unit to be appended at the end, can be NULL
- * @param fraction number of fractional digits of fractional digits
+ * @param scaling fixed point integer arithmetics scaling factor
  * @param raw true if the whole text conversion should be bypassed
  *   and only the raw number shall be written, false otherwise
  * @return pointer to converted string
  */
 const char *
-isonumber_from_s64(struct isonumber_str *out, int64_t number, const char *unit, int fraction, bool raw) {
+isonumber_from_s64(struct isonumber_str *out, int64_t number, const char *unit, uint64_t scaling, bool raw) {
   char *outbuf = out->buf;
   uint64_t num;
   size_t len;
@@ -107,7 +107,7 @@ isonumber_from_s64(struct isonumber_str *out, int64_t number, const char *unit,
     num = (uint64_t)number;
   }
 
-  if (_isonumber_u64_to_string(outbuf, len, num, unit, fraction, raw)) {
+  if (_isonumber_u64_to_string(outbuf, len, num, unit, scaling, raw)) {
     return out->buf;
   }
   return NULL;
@@ -118,11 +118,11 @@ isonumber_from_s64(struct isonumber_str *out, int64_t number, const char *unit,
  * to a signed 64bit integer.
  * @param dst pointer to destination variable
  * @param iso pointer to string source
- * @param fractions number of fractional digits, might be zero
+ * @param scaling fixed point integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 int
-isonumber_to_s64(int64_t *dst, const char *iso, int fractions) {
+isonumber_to_s64(int64_t *dst, const char *iso, uint64_t scaling) {
   const char *ptr;
   int result;
   uint64_t u64;
@@ -132,7 +132,7 @@ isonumber_to_s64(int64_t *dst, const char *iso, int fractions) {
     ptr++;
   }
 
-  result = isonumber_to_u64(&u64, ptr, fractions);
+  result = isonumber_to_u64(&u64, ptr, scaling);
   if (!result) {
     if (*iso == '-') {
       *dst = -((int64_t)u64);
@@ -149,16 +149,14 @@ isonumber_to_s64(int64_t *dst, const char *iso, int fractions) {
  * to an unsigned 64bit integer.
  * @param dst pointer to destination variable
  * @param iso pointer to string source
- * @param fraction number of fractional digits, might be zero
+ * @param scaling fixed point integer arithmetics scaling factor
  * @return -1 if an error happened, 0 otherwise
  */
 int
-isonumber_to_u64(uint64_t *dst, const char *iso, int fraction) {
+isonumber_to_u64(uint64_t *dst, const char *iso, uint64_t scaling) {
   static const char symbol_large[] = " kMGTPE";
 
-  uint64_t num;
-  uint64_t factor;
-  int frac;
+  uint64_t num, fraction_scale, factor;
   char *next = NULL, *prefix;
 
   errno = 0;
@@ -168,27 +166,30 @@ isonumber_to_u64(uint64_t *dst, const char *iso, int fraction) {
   }
 
   if (*next == 0) {
-    for (frac = 0; frac < fraction; frac++) {
-      num *= 10;
+    if (num > UINT64_MAX / scaling) {
+      /* this would be an integer overflow */
+      return -1;
     }
-    *dst = num;
+
+    *dst = num * scaling;
     return 0;
   }
 
   /* Handle fractional part */
-  frac = 0;
+  fraction_scale = 1;
   if (*next == '.') {
     next++;
     while (*next >= '0' && *next <= '9') {
       num *= 10;
       num += (*next - '0');
-      frac++;
+      fraction_scale *= 10;
       next++;
     }
   }
-  while (frac < fraction) {
+  while (fraction_scale < scaling && (scaling % 10) == 0) {
     num *= 10;
-    frac++;
+    fraction_scale *= 10;
+    scaling /= 10;
   }
 
   /* handle spaces */
@@ -214,8 +215,8 @@ isonumber_to_u64(uint64_t *dst, const char *iso, int fraction) {
     }
   }
 
-  while (frac > fraction) {
-    frac -= 3;
+  while (fraction_scale > scaling) {
+    fraction_scale /= 1000;
     if (factor > 1) {
       factor /= 1000;
     }
@@ -223,12 +224,13 @@ isonumber_to_u64(uint64_t *dst, const char *iso, int fraction) {
       num /= 1000;
     }
   }
-  if (num > UINT64_MAX / factor) {
+
+  if (num > UINT64_MAX / (factor*scaling)) {
     /* this would be an integer overflow */
     return -1;
   }
 
-  *dst = num * factor;
+  *dst = num * factor * scaling;
   return 0;
 }
 
@@ -240,43 +242,36 @@ isonumber_to_u64(uint64_t *dst, const char *iso, int fraction) {
  * @param out_len length of output buffer
  * @param number number to convert
  * @param unit unit that should be appended on result
- * @param fraction number of fractional digits
+ * @param scaling fixed point integer arithmetics scaling factor
  * @param raw true to suppress iso prefixes and unit, false otherwise
  * @return pointer to output buffer, NULL if an error happened
  */
 static const char *
-_isonumber_u64_to_string(char *out, size_t out_len, uint64_t number, const char *unit, size_t fraction, bool raw) {
+_isonumber_u64_to_string(char *out, size_t out_len, uint64_t number, const char *unit, uint64_t scaling, bool raw) {
   static const char symbol_large[] = " kMGTPE";
   static const char symbol_small[] = " munpfa";
-  uint64_t multiplier, print, n;
+  uint64_t print, n;
   const char *unit_modifier;
   size_t idx, len;
-  int result;
+  int result, fraction;
 
-  multiplier = 1;
-
-  while (fraction > 0) {
-    multiplier *= 10;
-    fraction--;
-  }
-
-  if (number >= multiplier) {
+  if (number >= scaling) {
     unit_modifier = symbol_large;
-    while (!raw && *unit_modifier != 0 && number / 1000 >= multiplier) {
-      multiplier *= 1000;
+    while (!raw && *unit_modifier != 0 && number / 1000 >= scaling) {
+      scaling *= 1000;
       unit_modifier++;
     }
   }
   else {
     unit_modifier = symbol_small;
-    while (!raw && *unit_modifier != 0 && number < multiplier && multiplier >= 1000) {
-      multiplier /= 1000;
+    while (!raw && *unit_modifier != 0 && number < scaling && scaling >= 1000) {
+      scaling /= 1000;
       unit_modifier++;
     }
   }
 
   /* print whole */
-  if ((result = snprintf(out, out_len, "%" PRIu64, number / multiplier)) < 0) {
+  if ((result = snprintf(out, out_len, "%" PRIu64, number / scaling)) < 0) {
     return NULL;
   }
 
@@ -288,16 +283,14 @@ _isonumber_u64_to_string(char *out, size_t out_len, uint64_t number, const char
 
   /* show three fractional digits */
   fraction = 3;
-
   while (true) {
-    n = n % multiplier;
+    n = n % scaling;
     if (n == 0 || fraction == 0) {
       break;
     }
     fraction--;
     n *= 10;
-
-    print = n / multiplier;
+    print = n / scaling;
 
     if (print >= 10) {
       return NULL;
index b75ed3b..b88047f 100644 (file)
@@ -108,12 +108,14 @@ int
 cfg_tobin_int(void *reference, size_t bin_size, const struct const_strarray *value, int fractions, size_t int_size) {
   int64_t i;
   int result;
+  uint64_t scaling;
 
   if (bin_size != int_size) {
     return -1;
   }
 
-  result = isonumber_to_s64(&i, strarray_get_first_c(value), fractions);
+  for (scaling = 1; fractions > 0; fractions--, scaling*=10);
+  result = isonumber_to_s64(&i, strarray_get_first_c(value), scaling);
   if (result == 0) {
     switch (int_size) {
       case 4:
@@ -277,7 +279,7 @@ cfg_tobin_stringlist(void *reference, size_t bin_size, const struct const_strarr
 int
 cfg_tobin_tokens(void *reference, const char *value, struct cfg_schema_entry *entries, size_t entry_count,
   struct cfg_schema_token_customizer *custom) {
-  struct const_strarray parameter;
+  struct const_strarray parameter, *parameter_ptr;
   const char *next_token;
   char buffer[256];
   char *dst;
@@ -289,13 +291,16 @@ cfg_tobin_tokens(void *reference, const char *value, struct cfg_schema_entry *en
   parameter.value = buffer;
   for (i = 0; i < entry_count - 1; i++) {
     if (!next_token) {
-      return -1;
+      parameter_ptr = &entries[i].def;
+    }
+    else {
+      next_token = str_cpynextword(buffer, next_token, sizeof(buffer));
+      parameter.length = strlen(parameter.value) + 1;
+      parameter_ptr = &parameter;
     }
-    next_token = str_cpynextword(buffer, next_token, sizeof(buffer));
-    parameter.length = strlen(parameter.value) + 1;
 
     if (entries[i].cb_to_binary) {
-      if (entries[i].cb_to_binary(&entries[i], &parameter, dst + entries[i].bin_offset)) {
+      if (entries[i].cb_to_binary(&entries[i], parameter_ptr, dst + entries[i].bin_offset)) {
         return -1;
       }
     }
index 0831936..d3ee669 100644 (file)
@@ -147,9 +147,11 @@ int
 cfg_validate_int(struct autobuf *out, const char *section_name, const char *entry_name, const char *value, int64_t min,
   int64_t max, uint16_t bytelen, uint16_t fraction) {
   int64_t i, min64, max64;
+  uint64_t scaling;
   struct isonumber_str hbuf;
 
-  if (isonumber_to_s64(&i, value, fraction)) {
+  for (scaling = 1; fraction > 0; fraction--, scaling*=10);
+  if (isonumber_to_s64(&i, value, scaling)) {
     if (fraction) {
       cfg_append_printable_line(out,
         "Value '%s' for entry '%s'"
@@ -180,14 +182,14 @@ cfg_validate_int(struct autobuf *out, const char *section_name, const char *entr
     cfg_append_printable_line(out,
       "Value '%s' for entry '%s' in section %s is "
       "smaller than %s",
-      value, entry_name, section_name, isonumber_from_s64(&hbuf, min, "", fraction, true));
+      value, entry_name, section_name, isonumber_from_s64(&hbuf, min, "", scaling, true));
     return -1;
   }
   if (i > max) {
     cfg_append_printable_line(out,
       "Value '%s' for entry '%s' in section %s is "
       "larger than %s",
-      value, entry_name, section_name, isonumber_from_s64(&hbuf, min, "", fraction, true));
+      value, entry_name, section_name, isonumber_from_s64(&hbuf, min, "", scaling, true));
     return -1;
   }
   return 0;
@@ -325,9 +327,11 @@ cfg_validate_tokens(struct autobuf *out, const char *section_name, const char *e
   char buffer[256];
   char section_name_entry[32];
   const char *ptr;
+  uint32_t parameter_count;
   size_t i;
 
-  if (str_countwords(value) < entry_count) {
+  parameter_count = str_countwords(value);
+  if (parameter_count < entry_count - custom->optional) {
     cfg_append_printable_line(out,
       "Missing token for entry '%s'"
       " in section %s. At least %" PRINTF_SIZE_T_SPECIFIER " tokens"
@@ -339,7 +343,7 @@ cfg_validate_tokens(struct autobuf *out, const char *section_name, const char *e
 
   /* check each token */
   ptr = value;
-  for (i = 0; i < entry_count - 1; i++) {
+  for (i = 0; i < parameter_count; i++) {
     ptr = str_cpynextword(buffer, ptr, sizeof(buffer));
 
     /* see if token is valid */
index 84e1657..771ce6a 100644 (file)
@@ -305,8 +305,9 @@ static struct oonf_timer_class _hello_lost_info = {
 
 /* layer2 originator for BC loss */
 static struct oonf_layer2_origin _ffdat_origin = {
-  .name = "ffdat bc loss",
+  .name = "ffdat measured data",
   .proactive = true,
+  /* not as reliable as we would like because we are measuring the broadcast loss */
   .priority = OONF_LAYER2_ORIGIN_RELIABLE - 1,
 };
 
@@ -614,7 +615,7 @@ _get_raw_rx_linkspeed(const char *ifname, struct nhdp_link *lnk) {
 
   rx_bitrate_entry = oonf_layer2_neigh_query(ifname, &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_BITRATE, true);
   if (rx_bitrate_entry) {
-    return oonf_layer2_data_get_int64(rx_bitrate_entry, 0);
+    return oonf_layer2_data_get_int64(rx_bitrate_entry, 1, 0);
   }
 
   l2net = oonf_layer2_net_get(ifname);
@@ -628,7 +629,7 @@ _get_raw_rx_linkspeed(const char *ifname, struct nhdp_link *lnk) {
     if (oonf_layer2_neigh_get_remote_ip(l2neigh, &lnk->if_addr)) {
       rx_bitrate_entry = &l2neigh->data[OONF_LAYER2_NEIGH_RX_BITRATE];
       if (oonf_layer2_data_has_value(rx_bitrate_entry)) {
-        return oonf_layer2_data_get_int64(rx_bitrate_entry, 0);
+        return oonf_layer2_data_get_int64(rx_bitrate_entry, 1, 0);
       }
     }
   }
@@ -869,56 +870,69 @@ _calculate_dynamic_loss_exponent(int link_neigborhood) {
 static uint32_t
 _apply_packet_loss(struct ff_dat_if_config *ifconfig, struct nhdp_link *lnk, struct link_datff_data *ldata,
     uint32_t metric, uint32_t received, uint32_t total) {
-  struct oonf_layer2_data *rx_bc_loss_entry;
-  int64_t success1_scaled_by_1000, success2_scaled_by_1000, success_scaled_by_1000;
-  int loss_exponent;
+  struct oonf_layer2_data *rx_bc_loss_entry, *rx_rlq_entry;
+  int64_t success_scaled_by_8000, probed_bc_loss_by_8000;
+  int loss_exponent, success_datapoint_count;
   int64_t tmp_metric;
 
+  success_datapoint_count = 0;
+  success_scaled_by_8000 = 0ll;
+  probed_bc_loss_by_8000 = 0ll;
+
   /* success based on received multicast frames */
-  if (total == 0 || received * DATFF_FRAME_SUCCESS_RANGE <= total) {
-    success1_scaled_by_1000 = 0ll;
-  }
-  else {
-    success1_scaled_by_1000 = (((int64_t)DATFF_FRAME_SUCCESS_RANGE * 1000ll) * received) / total;
+  if (total != 0 && received * DATFF_FRAME_SUCCESS_RANGE > total) {
+    probed_bc_loss_by_8000 = (((int64_t)DATFF_FRAME_SUCCESS_RANGE * 1000ll) * received) / total;
+    success_scaled_by_8000 += probed_bc_loss_by_8000;
+    success_datapoint_count++;
   }
 
   /* success based on layer2 broadcast loss */
   rx_bc_loss_entry = oonf_layer2_neigh_query(nhdp_interface_get_name(lnk->local_if),
     &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_BC_LOSS, false);
   if (rx_bc_loss_entry && oonf_layer2_data_get_origin(rx_bc_loss_entry) != &_ffdat_origin) {
-    success2_scaled_by_1000 = 1000 - oonf_layer2_data_get_int64(rx_bc_loss_entry, 0);
-  }
-  else {
-    if (success1_scaled_by_1000 > 0) {
-      rx_bc_loss_entry = oonf_layer2_neigh_add_path(nhdp_interface_get_name(lnk->local_if),
-          &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_BC_LOSS);
-      if (rx_bc_loss_entry) {
-        oonf_layer2_data_set_int64(rx_bc_loss_entry, &_ffdat_origin, 1000 - success1_scaled_by_1000);
-      }
+    success_scaled_by_8000 += (8000ll - oonf_layer2_data_get_int64(rx_bc_loss_entry, 8000, 0));
+    success_datapoint_count++;
+  }
+  else if (probed_bc_loss_by_8000 > 0) {
+    rx_bc_loss_entry = oonf_layer2_neigh_add_path(nhdp_interface_get_name(lnk->local_if),
+        &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_BC_LOSS);
+    if (rx_bc_loss_entry) {
+      oonf_layer2_data_set_int64(rx_bc_loss_entry, &_ffdat_origin, NULL, 8000ll - probed_bc_loss_by_8000, 8000);
     }
-    success2_scaled_by_1000 = 0ll;
   }
 
-  /* calculate mean success if necessary */
-  success_scaled_by_1000 = success1_scaled_by_1000 + success2_scaled_by_1000;
-  if (success1_scaled_by_1000 > 0 && success2_scaled_by_1000 > 0) {
-    success_scaled_by_1000 = success_scaled_by_1000 / 2;
+  /* RLQ handling */
+  rx_rlq_entry = oonf_layer2_neigh_query(nhdp_interface_get_name(lnk->local_if),
+    &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_RLQ, false);
+  if (rx_rlq_entry && oonf_layer2_data_get_origin(rx_rlq_entry) != &_ffdat_origin) {
+    success_scaled_by_8000 += 80ll * oonf_layer2_data_get_int64(rx_rlq_entry, 8000, 0);
+    success_datapoint_count++;
+  }
+  else if (probed_bc_loss_by_8000 > 0) {
+    rx_rlq_entry = oonf_layer2_neigh_add_path(nhdp_interface_get_name(lnk->local_if),
+        &lnk->remote_mac, OONF_LAYER2_NEIGH_RX_RLQ);
+    if (rx_rlq_entry) {
+      oonf_layer2_data_set_int64(rx_rlq_entry, &_ffdat_origin, NULL, probed_bc_loss_by_8000, 8000);
+    }
   }
 
   /* make sure we have someone meaningful */
-  if (success_scaled_by_1000 == 0) {
+  if (success_datapoint_count == 0) {
     return metric * DATFF_FRAME_SUCCESS_RANGE;
   }
 
+  /* calculate mean success if necessary */
+  success_scaled_by_8000 /= success_datapoint_count;
+
   /* hysteresis */
-  if (success_scaled_by_1000 >= ldata->last_packet_success_rate - 750 &&
-      success_scaled_by_1000 <= ldata->last_packet_success_rate + 750) {
+  if (success_scaled_by_8000 >= ldata->last_packet_success_rate - 750 &&
+      success_scaled_by_8000 <= ldata->last_packet_success_rate + 750) {
     /* keep old loss rate */
-    success_scaled_by_1000 = ldata->last_packet_success_rate;
+    success_scaled_by_8000 = ldata->last_packet_success_rate;
   }
   else {
     /* remember new loss rate */
-    ldata->last_packet_success_rate = success_scaled_by_1000;
+    ldata->last_packet_success_rate = success_scaled_by_8000;
   }
 
   _calculate_link_neighborhood(lnk, ldata);
@@ -943,7 +957,7 @@ _apply_packet_loss(struct ff_dat_if_config *ifconfig, struct nhdp_link *lnk, str
 
   tmp_metric = metric;
   while (loss_exponent) {
-    tmp_metric = (tmp_metric * (int64_t)DATFF_FRAME_SUCCESS_RANGE * 1000ll + 500ll) / success_scaled_by_1000;
+    tmp_metric = (tmp_metric * (int64_t)DATFF_FRAME_SUCCESS_RANGE * 1000ll + 500ll) / success_scaled_by_8000;
     loss_exponent--;
   }
 
index a43d812..bd5ee6e 100644 (file)
@@ -320,7 +320,7 @@ _cb_probe_link(struct oonf_timer_instance *ptr __attribute__((unused))) {
 
       /* fix tx-packets */
       last_tx_packets = ldata->last_tx_traffic;
-      ldata->last_tx_traffic = oonf_layer2_data_get_int64(&l2neigh->data[OONF_LAYER2_NEIGH_TX_FRAMES], 0);
+      ldata->last_tx_traffic = oonf_layer2_data_get_int64(&l2neigh->data[OONF_LAYER2_NEIGH_TX_FRAMES], 1, 0);
 
       /* check if link had traffic since last probe check */
       if (last_tx_packets != ldata->last_tx_traffic) {
index 5da4ad8..86551ab 100644 (file)
@@ -65,7 +65,7 @@ test_str_from_isonumber_u64(void) {
   };
   static uint64_t tests[] = { 1000, 1024, 1000*1000, 1000*1024, 1024*1024 };
   struct isonumber_str buf;
-  uint64_t diff;
+  uint64_t diff, scaling;
   size_t i;
 
   const char *tmp;
@@ -73,15 +73,17 @@ test_str_from_isonumber_u64(void) {
 
   START_TEST();
 
-  for (diff=0; diff < 3; diff++) {
-    for (i=0; i<5; i++) {
-      tmp = isonumber_from_u64(&buf, tests[i]+diff-1, NULL, 0, false);
-      correct = tmp != NULL && strcmp(tmp, results[diff][i]) == 0;
+  for (scaling = 1; scaling <= 64; scaling *= 4) {
+    for (diff=0; diff < 3; diff++) {
+      for (i=0; i<5; i++) {
+        tmp = isonumber_from_u64(&buf, (tests[i]+diff-1)*scaling, NULL, scaling, false);
+        correct = tmp != NULL && strcmp(tmp, results[diff][i]) == 0;
 
-      CHECK_TRUE(tmp != NULL, "isonumber_from_u64(%"PRIu64") is not null",
-          tests[i]+diff-1);
-       CHECK_TRUE(correct, "isonumber_from_u64(%"PRIu64") = %s should be %s",
+        CHECK_TRUE(tmp != NULL, "isonumber_from_u64(%"PRIu64") is not null",
+            tests[i]+diff-1);
+        CHECK_TRUE(correct, "isonumber_from_u64(%"PRIu64") = %s should be %s",
                        tests[i]+diff-1, tmp, results[diff][i]);
+      }
     }
   }
 
@@ -96,19 +98,21 @@ test_isonumber_to_u64_to_string(void) {
   static uint64_t results[] = { 1000, 1024, 1000*1000, 1000*1024, 1023 };
 
   size_t i;
-
+  int64_t scaling;
   uint64_t result;
   int tmp;
 
   START_TEST();
 
-  for (i=0; i<ARRAYSIZE(tests); i++) {
-    result = 0;
-    tmp = isonumber_to_u64(&result, tests[i], 0);
-    CHECK_TRUE(tmp == 0, "isonumber_to_u64(\"%s\") failed", tests[i]);
-    if (!tmp) {
-      CHECK_TRUE(result== results[i], "isonumber_to_u64(\"%s\") != %"PRIu64" (was %"PRIu64")",
-          tests[i], results[i], result);
+  for (scaling = 1; scaling <= 64; scaling *= 4) {
+    for (i=0; i<ARRAYSIZE(tests); i++) {
+      result = 0;
+      tmp = isonumber_to_u64(&result, tests[i], scaling);
+      CHECK_TRUE(tmp == 0, "isonumber_to_u64(\"%s\") failed", tests[i]);
+      if (!tmp) {
+        CHECK_TRUE(result == results[i]*scaling, "isonumber_to_u64(\"%s\") != %"PRIu64" (was %"PRIu64")",
+            tests[i], results[i]*scaling, result);
+      }
     }
   }
   END_TEST();
@@ -134,7 +138,7 @@ test_isonumber_to_s64_to_string(void) {
 
   for (i=0; i<ARRAYSIZE(tests); i++) {
     result = 0;
-    tmp = isonumber_to_s64(&result, tests[i], 0);
+    tmp = isonumber_to_s64(&result, tests[i], 1);
     CHECK_TRUE(tmp == 0, "isonumber_to_u64(\"%s\") failed", tests[i]);
     if (!tmp) {
       CHECK_TRUE(result== results[i], "isonumber_to_u64(\"%s\") != %"PRId64" (was %"PRId64")",
@@ -163,7 +167,7 @@ test_str_from_isonumber_s64(void) {
 
   for (diff=0; diff < 3; diff++) {
     for (i=0; i<5; i++) {
-      tmp = isonumber_from_s64(&buf, tests[i]-diff+1, NULL, 0, false);
+      tmp = isonumber_from_s64(&buf, tests[i]-diff+1, NULL, 1, false);
       correct = tmp != NULL && strcmp(tmp, results[diff][i]) == 0;
 
       CHECK_TRUE(tmp != NULL, "str_to_isonumber_s64(%"PRId64") is not null",
@@ -184,7 +188,7 @@ test_str_from_isonumber_s64_2(void) {
 
   CHECK_TRUE(
       isonumber_from_s64(&buf,
-          5185050545986994176ll, "bit/s", 0, false) != NULL, "test");
+          5185050545986994176ll, "bit/s", 1, false) != NULL, "test");
   END_TEST();
 }