Change lqplugin system so plugins can have multiple values for each link (not only...
authorHenning Rogge <hrogge@googlemail.com>
Sat, 8 Aug 2009 10:49:49 +0000 (12:49 +0200)
committerHenning Rogge <hrogge@googlemail.com>
Sat, 8 Aug 2009 10:49:49 +0000 (12:49 +0200)
Add range, quality and name information for each of the lq parameters.
Add simple template engine
Convert txtinfo to template engine

29 files changed:
lib/bmf/src/NetworkInterfaces.c
lib/debuginfo/src/olsrd_debuginfo.c
lib/debuginfo/src/olsrd_debuginfo.h
lib/dot_draw/src/olsrd_dot_draw.c
lib/httpinfo/src/olsrd_httpinfo.c
lib/lq_etx_ff/src/lq_plugin_etx_ff.c
lib/lq_etx_float/src/lq_plugin_etx_float.c
lib/lq_etx_fpm/src/lq_plugin_etx_fpm.c
lib/lq_rfc/src/lq_plugin_rfc.c
lib/nameservice/src/mapwrite.c
lib/nameservice/src/nameservice.c
lib/txtinfo/src/olsrd_txtinfo.c
src/common/autobuf.c
src/common/autobuf.h
src/common/string.c
src/common/string.h
src/link_set.c
src/link_set.h
src/lq_mpr.c
src/lq_plugin.c
src/lq_plugin.h
src/neighbor_table.c
src/olsr_comport.c
src/olsr_comport.h
src/olsr_comport_txt.c
src/olsr_comport_txt.h
src/olsr_spf.c
src/routing_table.c
src/tc_set.c

index ed9482c..0dfffc8 100644 (file)
@@ -481,12 +481,13 @@ FindNeighbors(struct TBestNeighbors *neighbors,
       } else {
 #if !defined REMOVE_LOG_DEBUG
         struct interface *bestIntf = if_ifwithaddr(&bestLinkToNeighbor->local_iface_addr);
-        struct lqtextbuffer lqbuffer;
+        char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
         OLSR_DEBUG(LOG_PLUGINS,
                    "Not forwarding to %s: \"%s\" gives a better link to this neighbor, costing %s\n",
                    olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
-                   bestIntf->int_name, get_linkcost_text(bestLinkToNeighbor->linkcost, false, &lqbuffer));
+                   bestIntf->int_name,
+                   olsr_get_linkcost_text(bestLinkToNeighbor->linkcost, false, lqbuffer, sizeof(lqbuffer)));
       }
 
       continue;                 /* for */
@@ -495,13 +496,13 @@ FindNeighbors(struct TBestNeighbors *neighbors,
     if (forwardedBy != NULL) {
 #if !defined REMOVE_LOG_DEBUG
       struct ipaddr_str forwardedByBuf, niaBuf;
-      struct lqtextbuffer lqbuffer;
+      char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
       OLSR_DEBUG(LOG_PLUGINS,
                  "2-hop path from %s via me to %s will cost ETX %s\n",
                  olsr_ip_to_string(&forwardedByBuf, forwardedBy),
                  olsr_ip_to_string(&niaBuf, &walker->neighbor_iface_addr),
-                 get_linkcost_text(previousLinkEtx + currEtx, true, &lqbuffer));
+                 olsr_get_linkcost_text(previousLinkEtx + currEtx, true, lqbuffer, sizeof(lqbuffer)));
     }
 
     /* Check the topology table whether the 'forwardedBy' node is itself a direct
@@ -522,14 +523,15 @@ FindNeighbors(struct TBestNeighbors *neighbors,
           if (previousLinkEtx + currEtx > tcEtx) {
 #if !defined REMOVE_LOG_DEBUG
             struct ipaddr_str neighbor_iface_buf, forw_buf;
-            struct lqtextbuffer lqbuffer;
+            char lqbuffer[LQTEXT_MAXLENGTH];
             olsr_ip_to_string(&neighbor_iface_buf, &walker->neighbor_iface_addr);
 #endif
             OLSR_DEBUG(LOG_PLUGINS,
                        "Not forwarding to %s: I am not an MPR between %s and %s, direct link costs %s\n",
                        neighbor_iface_buf.buf,
                        olsr_ip_to_string(&forw_buf, forwardedBy),
-                       neighbor_iface_buf.buf, get_linkcost_text(tcEtx, false, &lqbuffer));
+                       neighbor_iface_buf.buf,
+                       olsr_get_linkcost_text(tcEtx, false, lqbuffer, sizeof(lqbuffer)));
 
             continue;           /* for */
           }                     /* if */
index be7c4d6..6915385 100644 (file)
@@ -69,7 +69,7 @@
 struct debuginfo_cmd {
   const char *name;
   olsr_txthandler handler;
-  struct olsr_txtcommand *normal, *csv;
+  struct olsr_txtcommand *cmd;
 };
 
 static void debuginfo_new(void) __attribute__ ((constructor));
@@ -100,9 +100,9 @@ static const struct olsrd_plugin_parameters plugin_parameters[] = {
 
 /* command callbacks and names */
 static struct debuginfo_cmd commands[] = {
-    {"msgstat", &debuginfo_msgstat, NULL, NULL},
-    {"pktstat", &debuginfo_pktstat, NULL, NULL},
-    {"cookies", &debuginfo_cookies, NULL, NULL}
+    {"msgstat", &debuginfo_msgstat, NULL},
+    {"pktstat", &debuginfo_pktstat, NULL},
+    {"cookies", &debuginfo_cookies, NULL}
 };
 
 /* variables for statistics */
@@ -169,8 +169,7 @@ debuginfo_delete(void)
   size_t i;
 
   for (i=0; i<ARRAYSIZE(commands); i++) {
-    olsr_com_remove_normal_txtcommand(commands[i].normal);
-    olsr_com_remove_csv_txtcommand(commands[i].csv);
+    olsr_com_remove_normal_txtcommand(commands[i].cmd);
   }
   olsr_parser_remove_function(&olsr_msg_statistics, PROMISCUOUS);
   olsr_preprocessor_remove_function(&olsr_packet_statistics);
@@ -183,10 +182,8 @@ olsrd_plugin_init(void)
   size_t i;
 
   for (i=0; i<ARRAYSIZE(commands); i++) {
-    commands[i].normal = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
-    commands[i].csv = olsr_com_add_csv_txtcommand(commands[i].name, commands[i].handler);
-    commands[i].normal->acl = &allowed_nets;
-    commands[i].csv->acl = &allowed_nets;
+    commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
+    commands[i].cmd->acl = &allowed_nets;
   }
 
   statistics_timer = olsr_alloc_cookie("debuginfo timer", OLSR_COOKIE_TYPE_TIMER);
@@ -395,21 +392,8 @@ static const char *debuginfo_print_trafficip(struct ipaddr_str *buf, union olsr_
   return olsr_ip_to_string(buf, ip);
 }
 
-static bool debuginfo_print_msgstat(struct autobuf *buf, bool csv, union olsr_ip_addr *ip, struct debug_msgtraffic_count *cnt) {
+static bool debuginfo_print_msgstat(struct autobuf *buf, union olsr_ip_addr *ip, struct debug_msgtraffic_count *cnt) {
   struct ipaddr_str strbuf;
-
-  if (csv) {
-    return abuf_appendf(buf, "msgstat,%s,%d,%d,%d,%d,%d,%d,%d\n",
-        debuginfo_print_trafficip(&strbuf, ip),
-        cnt->data[DTR_HELLO],
-        cnt->data[DTR_TC],
-        cnt->data[DTR_MID],
-        cnt->data[DTR_HNA],
-        cnt->data[DTR_OTHER],
-        cnt->data[DTR_MESSAGES],
-        cnt->data[DTR_MSG_TRAFFIC]) < 0;
-  }
-
   return abuf_appendf(buf, "%-*s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n",
       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
       cnt->data[DTR_HELLO],
@@ -426,21 +410,19 @@ debuginfo_msgstat(struct comport_connection *con,  char *cmd __attribute__ ((unu
 {
   struct debug_msgtraffic *tr;
 
-  if (!con->is_csv) {
-    if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
-      return ABUF_ERROR;
-    }
-    if (abuf_appendf(&con->out,
-        "Table: Statistics (without duplicates)\n%-*s\tHello\tTC\tMID\tHNA\tOther\tTotal\tBytes\n",
-        olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
-        ) < 0) {
-      return ABUF_ERROR;
-    }
+  if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
+    return ABUF_ERROR;
+  }
+  if (abuf_appendf(&con->out,
+      "Table: Statistics (without duplicates)\n%-*s\tHello\tTC\tMID\tHNA\tOther\tTotal\tBytes\n",
+      olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
+      ) < 0) {
+    return ABUF_ERROR;
   }
 
   if (param == NULL || strcasecmp(param, "node") == 0) {
     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr) {
-      if (debuginfo_print_msgstat(&con->out, con->is_csv, &tr->ip, &tr->traffic[current_slot])) {
+      if (debuginfo_print_msgstat(&con->out, &tr->ip, &tr->traffic[current_slot])) {
         return ABUF_ERROR;
       }
     } OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES_END(tr)
@@ -477,7 +459,7 @@ debuginfo_msgstat(struct comport_connection *con,  char *cmd __attribute__ ((unu
       for (i=0; i<DTR_MSG_COUNT; i++) {
         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
       }
-      if (debuginfo_print_msgstat(&con->out, con->is_csv, &tr->ip, &cnt)) {
+      if (debuginfo_print_msgstat(&con->out, &tr->ip, &cnt)) {
         return ABUF_ERROR;
       }
     } OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES_END(tr)
@@ -486,17 +468,8 @@ debuginfo_msgstat(struct comport_connection *con,  char *cmd __attribute__ ((unu
   return CONTINUE;
 }
 
-static bool debuginfo_print_pktstat(struct autobuf *buf, bool csv, union olsr_ip_addr *ip, char *int_name, struct debug_pkttraffic_count *cnt) {
+static bool debuginfo_print_pktstat(struct autobuf *buf, union olsr_ip_addr *ip, char *int_name, struct debug_pkttraffic_count *cnt) {
   struct ipaddr_str strbuf;
-
-  if (csv) {
-    return abuf_appendf(buf, "msgstat,%s,%s,%d,%d\n",
-        debuginfo_print_trafficip(&strbuf, ip),
-        int_name,
-        cnt->data[DTR_PACKETS],
-        cnt->data[DTR_PACK_TRAFFIC]) < 0;
-  }
-
   return abuf_appendf(buf, "%-*s\t%s\t%d\t%d\n",
       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
       int_name,
@@ -509,21 +482,19 @@ debuginfo_pktstat(struct comport_connection *con,  char *cmd __attribute__ ((unu
 {
   struct debug_pkttraffic *tr;
 
-  if (!con->is_csv) {
-    if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
-      return ABUF_ERROR;
-    }
-    if (abuf_appendf(&con->out,
-        "Table: Statistics (without duplicates)\n%-*s\tInterf.\tPackets\tBytes\n",
-        olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
-        ) < 0) {
-      return ABUF_ERROR;
-    }
+  if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
+    return ABUF_ERROR;
+  }
+  if (abuf_appendf(&con->out,
+      "Table: Statistics (without duplicates)\n%-*s\tInterf.\tPackets\tBytes\n",
+      olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
+      ) < 0) {
+    return ABUF_ERROR;
   }
 
   if (param == NULL || strcasecmp(param, "node") == 0) {
     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr) {
-      if (debuginfo_print_pktstat(&con->out, con->is_csv, &tr->ip, tr->int_name, &tr->traffic[current_slot])) {
+      if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &tr->traffic[current_slot])) {
         return ABUF_ERROR;
       }
     } OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES_END(tr)
@@ -560,7 +531,7 @@ debuginfo_pktstat(struct comport_connection *con,  char *cmd __attribute__ ((unu
       for (i=0; i<DTR_PKT_COUNT; i++) {
         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
       }
-      if (debuginfo_print_pktstat(&con->out, con->is_csv, &tr->ip, tr->int_name, &cnt)) {
+      if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &cnt)) {
         return ABUF_ERROR;
       }
     } OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES_END(tr)
@@ -603,21 +574,19 @@ static INLINE bool debuginfo_print_cookies_timer(struct autobuf *buf, const char
 static enum olsr_txtcommand_result
 debuginfo_cookies(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused)))
 {
-  if (!con->is_csv && abuf_puts(&con->out, "Memory cookies:\n") < 0) {
+  if (abuf_puts(&con->out, "Memory cookies:\n") < 0) {
     return ABUF_ERROR;
   }
 
-  if (debuginfo_print_cookies_mem(&con->out, !con->is_csv ?
-      "%-25s (MEMORY) size: %lu usage: %u freelist: %u\n" : "mem_cookie,%s,%lu,%u,%u\n")) {
+  if (debuginfo_print_cookies_mem(&con->out, "%-25s (MEMORY) size: %lu usage: %u freelist: %u\n")) {
     return ABUF_ERROR;
   }
 
-  if (!con->is_csv && abuf_puts(&con->out, "\nTimer cookies:\n") < 0) {
+  if (abuf_puts(&con->out, "\nTimer cookies:\n") < 0) {
     return ABUF_ERROR;
   }
 
-  if (debuginfo_print_cookies_timer(&con->out, !con->is_csv ?
-      "%-25s (TIMER) usage: %u changes: %u\n" : "tmr_cookie,%s,%u,%u\n")) {
+  if (debuginfo_print_cookies_timer(&con->out, "%-25s (TIMER) usage: %u changes: %u\n")) {
     return ABUF_ERROR;
   }
   return CONTINUE;
index 83aeb7c..8e1462e 100644 (file)
@@ -43,8 +43,8 @@
  * Dynamic linked library for the olsr.org olsr daemon
  */
 
-#ifndef _OLSRD_TXTINFO
-#define _OLSRD_TXTINFO
+#ifndef _OLSRD_DEBUGINFO
+#define _OLSRD_DEBUGINFO
 
 #include "olsr_types.h"
 #include "plugin.h"
index badcb98..6389937 100644 (file)
@@ -147,7 +147,7 @@ ipc_print_neigh_link(int ipc_connection, const struct nbr_entry *neighbor)
   olsr_linkcost etx = 0.0;
   const char *style;
   const char *adr = olsr_ip_to_string(&mainaddrstrbuf, &olsr_cnf->router_id);
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 
   if (neighbor->is_sym == 0) {  /* non SYM */
     style = "dashed";
@@ -161,7 +161,8 @@ ipc_print_neigh_link(int ipc_connection, const struct nbr_entry *neighbor)
 
   ipc_send_fmt(ipc_connection,
                "\"%s\" -> \"%s\"[label=\"%s\", style=%s];\n",
-               adr, olsr_ip_to_string(&strbuf, &neighbor->nbr_addr), get_linkcost_text(etx, false, &lqbuffer), style);
+               adr, olsr_ip_to_string(&strbuf, &neighbor->nbr_addr),
+               olsr_get_linkcost_text(etx, false, lqbuffer, sizeof(lqbuffer)), style);
 
   if (neighbor->is_mpr) {
     ipc_send_fmt(ipc_connection, "\"%s\"[shape=box];\n", adr);
@@ -313,12 +314,13 @@ static void
 ipc_print_tc_link(int ipc_connection, const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
 {
   struct ipaddr_str strbuf1, strbuf2;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 
   ipc_send_fmt(ipc_connection,
                "\"%s\" -> \"%s\"[label=\"%s\"];\n",
                olsr_ip_to_string(&strbuf1, &entry->addr),
-               olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr), get_linkcost_text(dst_entry->cost, false, &lqbuffer));
+               olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr),
+               olsr_get_linkcost_text(dst_entry->cost, false, lqbuffer, sizeof(lqbuffer)));
 }
 
 
index 149b323..f667dce 100644 (file)
@@ -63,7 +63,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <unistd.h>
 #include <errno.h>
 #ifdef WIN32
@@ -755,14 +754,14 @@ build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_i
 static void
 build_route(struct autobuf *abuf, const struct rt_entry *rt)
 {
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 
   abuf_puts(abuf, "<tr>");
   build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
   build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
 
   abuf_appendf(abuf, "<td>%u</td>", rt->rt_best->rtp_metric.hops);
-  abuf_appendf(abuf, "<td>%s</td>", get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
+  abuf_appendf(abuf, "<td>%s</td>", olsr_get_linkcost_text(rt->rt_best->rtp_metric.cost, true, lqbuffer, sizeof(lqbuffer)));
   abuf_appendf(abuf,
                "<td>%s</td></tr>\n", rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]");
 }
@@ -928,23 +927,29 @@ build_neigh_body(struct autobuf *abuf)
 {
   struct nbr_entry *neigh;
   struct link_entry *lnk;
+  size_t i;
   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
 
   section_title(abuf, "Links");
 
   abuf_appendf(abuf, "<tr><th%s>Local IP</th><th%s>Remote IP</th>", colspan, colspan);
+  for (i=1; i<olsr_get_linklabel_count(); i++) {
+    abuf_appendf(abuf, "<th>%s</th>", olsr_get_linklabel(i));
+  }
   abuf_puts(abuf, "<th>LinkCost</th>");
   abuf_puts(abuf, "</tr>\n");
 
   /* Link set */
   OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
-    struct lqtextbuffer lqbuffer1, lqbuffer2;
+    char lqbuffer[LQTEXT_MAXLENGTH];
     abuf_puts(abuf, "<tr>");
     build_ipaddr_with_link(abuf, &lnk->local_iface_addr, -1);
     build_ipaddr_with_link(abuf, &lnk->neighbor_iface_addr, -1);
-    abuf_appendf(abuf,
-                 "<td>(%s) %s</td>",
-                 get_link_entry_text(lnk, '/', &lqbuffer1), get_linkcost_text(lnk->linkcost, false, &lqbuffer2));
+
+    for (i=1; i<olsr_get_linklabel_count(); i++) {
+      abuf_appendf(abuf, "<td>%s</td>", olsr_get_linkdata_text(lnk, i, lqbuffer, sizeof(lqbuffer)));
+    }
+    abuf_appendf(abuf, "<td>%s</td>", olsr_get_linkcost_text(lnk->linkcost, false, lqbuffer, sizeof(lqbuffer)));
     abuf_puts(abuf, "</tr>\n");
   } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
 
@@ -999,13 +1004,12 @@ build_topo_body(struct autobuf *abuf)
     struct tc_edge_entry *tc_edge;
     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
       if (tc_edge->edge_inv) {
-        struct lqtextbuffer lqbuffer1, lqbuffer2;
+        char lqbuffer[LQTEXT_MAXLENGTH];
         abuf_puts(abuf, "<tr>");
         build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
         build_ipaddr_with_link(abuf, &tc->addr, -1);
-        abuf_appendf(abuf,
-                     "<td>(%s)</td><td>&nbsp;</td><td>%s</td>\n",
-                     get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
+        abuf_appendf(abuf, "<td colspan=\"3\">%s</td>\n",
+                     olsr_get_linkcost_text(tc_edge->cost, false, lqbuffer, sizeof(lqbuffer)));
         abuf_puts(abuf, "</tr>\n");
       }
     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
index c6bbd8e..8a593dc 100644 (file)
@@ -50,6 +50,7 @@
 #include "mid_set.h"
 #include "scheduler.h"
 #include "olsr_logging.h"
+#include "common/string.h"
 
 #define PLUGIN_DESCR "Freifunk ETX metric based on the original design of Elektra and Thomas Lopatic"
 #define PLUGIN_AUTHOR "Henning Rogge"
@@ -86,15 +87,21 @@ static int lq_etxff_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *lq)
 static void lq_etxff_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *lq);
 static void lq_etxff_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *lq);
 
-static char *lq_etxff_print_link_entry_lq(struct link_entry *entry, char separator, struct lqtextbuffer *buffer);
-static char *lq_etxff_print_tc_edge_entry_lq(struct tc_edge_entry *ptr, char separator, struct lqtextbuffer *buffer);
-static char *lq_etxff_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer);
+static int lq_etxff_get_linkentry_data(struct link_entry *, int);
+static const char *lq_etxff_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize);
+static const char *lq_etxff_print_link_entry_lq(struct link_entry *entry, int index, char *buffer, size_t bufsize);
 
 static struct olsr_cookie_info *default_lq_ff_timer_cookie = NULL;
 
 DEFINE_PLUGIN6_NP(PLUGIN_DESCR, PLUGIN_AUTHOR, NULL, lq_etxff_post_init, NULL, NULL, false)
 
 /* etx lq plugin (freifunk fpm version) settings */
+struct lq_linkdata_type lq_etxff_linktypes[] = {
+  { "ETX", 5, 65536, 65536*2, 65536*4, INT32_MAX },
+  { "LQ", 5, 255, 240, 192, 0 },
+  { "NLQ", 5, 255, 240, 192, 0 }
+};
+
 struct lq_handler lq_etxff_handler = {
   "etx (freifunk)",
 
@@ -125,9 +132,12 @@ struct lq_handler lq_etxff_handler = {
   &lq_etxff_deserialize_hello_lq,
   &lq_etxff_deserialize_tc_lq,
 
-  &lq_etxff_print_link_entry_lq,
-  &lq_etxff_print_tc_edge_entry_lq,
+  &lq_etxff_get_linkentry_data,
   &lq_etxff_print_cost,
+  &lq_etxff_print_link_entry_lq,
+
+  lq_etxff_linktypes,
+  ARRAYSIZE(lq_etxff_linktypes),
 
   sizeof(struct lq_etxff_tc_edge),
   sizeof(struct lq_etxff_tc_mpr_addr),
@@ -429,52 +439,42 @@ lq_etxff_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *edge)
   pkt_ignore_u16(curr);
 }
 
-static char *
-lq_etxff_print_lq(struct lq_etxff_linkquality *lq, char separator, struct lqtextbuffer *buffer)
+static int
+lq_etxff_get_linkentry_data(struct link_entry *link, int idx) {
+  struct lq_etxff_link_entry *lq = (struct lq_etxff_link_entry *)link;
+  return idx == 1 ? lq->lq.valueLq : lq->lq.valueNlq;
+}
+
+static const char *
+lq_etxff_print_link_entry_lq(struct link_entry *link, int idx, char *buffer, size_t bufsize)
 {
-  int i = 0;
+  struct lq_etxff_link_entry *lq = (struct lq_etxff_link_entry *)link;
+  uint8_t value;
 
-  if (lq->valueLq == 255) {
-    strcpy(buffer->buf, "1.000");
-    i += 5;
-  else {
-    i = sprintf(buffer->buf, "0.%03d", (lq->valueLq * 1000) / 255);
+  if (idx == 1) {
+    value = lq->lq.valueLq;
+  }
+  else {
+    value = lq->lq.valueNlq;
   }
-  buffer->buf[i++] = separator;
 
-  if (lq->valueNlq == 255) {
-    strcpy(&buffer->buf[i], "1.000");
+  if (value == 255) {
+    strscpy(buffer, "1.000", bufsize);
   } else {
-    sprintf(&buffer->buf[i], "0.%03d", (lq->valueNlq * 1000) / 255);
+    snprintf(buffer, bufsize, "0.%03d", (value * 1000) / 255);
   }
-  return buffer->buf;
-}
-
-static char *
-lq_etxff_print_link_entry_lq(struct link_entry *link, char separator, struct lqtextbuffer *buffer)
-{
-  struct lq_etxff_link_entry *lq_link = (struct lq_etxff_link_entry *)link;
-
-  return lq_etxff_print_lq(&lq_link->lq, separator, buffer);
-}
-
-static char *
-lq_etxff_print_tc_edge_entry_lq(struct tc_edge_entry *edge, char separator, struct lqtextbuffer *buffer)
-{
-  struct lq_etxff_tc_edge *lq_edge = (struct lq_etxff_tc_edge *)edge;
-
-  return lq_etxff_print_lq(&lq_edge->lq, separator, buffer);
+  return buffer;
 }
 
-static char *
-lq_etxff_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer)
+static const char *
+lq_etxff_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize)
 {
   // must calculate
   uint32_t roundDown = cost >> 16;
   uint32_t fraction = ((cost & 0xffff) * 1000) >> 16;
 
-  sprintf(buffer->buf, "%u.%03u", roundDown, fraction);
-  return buffer->buf;
+  snprintf(buffer, bufsize, "%u.%03u", roundDown, fraction);
+  return buffer;
 }
 
 /*
index 2feddad..61f6723 100644 (file)
@@ -78,11 +78,17 @@ static int lq_etxfloat_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *
 static void lq_etxfloat_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *lq);
 static void lq_etxfloat_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *lq);
 
-static char *lq_etxfloat_print_link_entry_lq(struct link_entry *entry, char separator, struct lqtextbuffer *buffer);
-static char *lq_etxfloat_print_tc_edge_entry_lq(struct tc_edge_entry *ptr, char separator, struct lqtextbuffer *buffer);
-static char *lq_etxfloat_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer);
+static int lq_etxfloat_get_linkentry_data(struct link_entry *, int);
+static const char *lq_etxfloat_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize);
+static const char *lq_etxfloat_print_link_entry_lq(struct link_entry *entry, int index, char *buffer, size_t bufsize);
+
+/* etx lq plugin (float version) settings */
+struct lq_linkdata_type lq_etxfloat_linktypes[] = {
+  { "ETX", 5, 1000, 1000*2, 1000*4, INT32_MAX },
+  { "LQ", 5, 255, 240, 192, 0 },
+  { "NLQ", 5, 255, 240, 192, 0 }
+};
 
-/* etx lq plugin (freifunk fpm version) settings */
 struct lq_handler lq_etxfloat_handler = {
   "etx (float)",
 
@@ -113,9 +119,12 @@ struct lq_handler lq_etxfloat_handler = {
   &lq_etxfloat_deserialize_hello_lq,
   &lq_etxfloat_deserialize_tc_lq,
 
-  &lq_etxfloat_print_link_entry_lq,
-  &lq_etxfloat_print_tc_edge_entry_lq,
+  &lq_etxfloat_get_linkentry_data,
   &lq_etxfloat_print_cost,
+  &lq_etxfloat_print_link_entry_lq,
+
+  lq_etxfloat_linktypes,
+  ARRAYSIZE(lq_etxfloat_linktypes),
 
   sizeof(struct lq_etxfloat_tc_edge),
   sizeof(struct lq_etxfloat_tc_mpr_addr),
@@ -329,35 +338,27 @@ lq_etxfloat_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *edge)
   lq_edge->lq.valueNlq = (float)nlq_value / 255.0;
 }
 
-static char *
-lq_etxfloat_print_lq(struct lq_etxfloat_linkquality *lq, char separator, struct lqtextbuffer *buffer)
-{
-  snprintf(buffer->buf, sizeof(struct lqtextbuffer), "%2.3f%c%2.3f", lq->valueLq, separator, lq->valueNlq);
-  return buffer->buf;
-}
-
-static char *
-lq_etxfloat_print_link_entry_lq(struct link_entry *link, char separator, struct lqtextbuffer *buffer)
-{
+static int lq_etxfloat_get_linkentry_data(struct link_entry *link, int idx) {
   struct lq_etxfloat_link_entry *lq_link = (struct lq_etxfloat_link_entry *)link;
+  float value =  idx == 1 ? lq_link->lq.valueLq : lq_link->lq.valueNlq;
 
-  return lq_etxfloat_print_lq(&lq_link->lq, separator, buffer);
+  return (int)(value * 1000);
 }
 
-static char *
-lq_etxfloat_print_tc_edge_entry_lq(struct tc_edge_entry *edge, char separator, struct lqtextbuffer *buffer)
+static const char *
+lq_etxfloat_print_link_entry_lq(struct link_entry *link, int idx, char *buffer, size_t bufsize)
 {
-  struct lq_etxfloat_tc_edge *lq_edge = (struct lq_etxfloat_tc_edge *)edge;
-
-  return lq_etxfloat_print_lq(&lq_edge->lq, separator, buffer);
+  struct lq_etxfloat_link_entry *lq_link = (struct lq_etxfloat_link_entry *)link;
+  snprintf(buffer, bufsize, "%2.3f",
+      idx==1 ? lq_link->lq.valueLq : lq_link->lq.valueNlq);
+  return buffer;
 }
 
-static char *
-lq_etxfloat_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer)
+static const char *
+lq_etxfloat_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize)
 {
-  // must calculate
-  snprintf(buffer->buf, sizeof(struct lqtextbuffer), "%2.3f", ((float)cost) / LQ_PLUGIN_LC_MULTIPLIER);
-  return buffer->buf;
+  snprintf(buffer, bufsize, "%2.3f", ((float)cost) / LQ_PLUGIN_LC_MULTIPLIER);
+  return buffer;
 }
 
 /*
index 714edc5..bd20978 100644 (file)
@@ -46,6 +46,7 @@
 #include "olsr.h"
 #include "lq_plugin_etx_fpm.h"
 #include "olsr_logging.h"
+#include "common/string.h"
 
 #define PLUGIN_DESCR    "Integer arithmetic based ETX metric with exponential aging"
 #define PLUGIN_AUTHOR   "Sven-Ola Tuecke and Henning Rogge"
@@ -79,11 +80,17 @@ static int lq_etxfpm_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *lq
 static void lq_etxfpm_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *lq);
 static void lq_etxfpm_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *lq);
 
-static char *lq_etxfpm_print_link_entry_lq(struct link_entry *entry, char separator, struct lqtextbuffer *buffer);
-static char *lq_etxfpm_print_tc_edge_entry_lq(struct tc_edge_entry *ptr, char separator, struct lqtextbuffer *buffer);
-static char *lq_etxfpm_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer);
+static int lq_etxfpm_get_linkentry_data(struct link_entry *, int);
+static const char *lq_etxfpm_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize);
+static const char *lq_etxfpm_print_link_entry_lq(struct link_entry *entry, int idx, char *buffer, size_t bufsize);
+
+/* etx lq plugin (fpm version) settings */
+struct lq_linkdata_type lq_etxfpm_linktypes[] = {
+  { "ETX", 5, 1000, 1000*2, 1000*4, INT32_MAX },
+  { "LQ", 5, 255, 240, 192, 0 },
+  { "NLQ", 5, 255, 240, 192, 0 }
+};
 
-/* etx lq plugin (freifunk fpm version) settings */
 struct lq_handler lq_etxfpm_handler = {
   "etx (fpm)",
 
@@ -114,9 +121,12 @@ struct lq_handler lq_etxfpm_handler = {
   &lq_etxfpm_deserialize_hello_lq,
   &lq_etxfpm_deserialize_tc_lq,
 
-  &lq_etxfpm_print_link_entry_lq,
-  &lq_etxfpm_print_tc_edge_entry_lq,
+  &lq_etxfpm_get_linkentry_data,
   &lq_etxfpm_print_cost,
+  &lq_etxfpm_print_link_entry_lq,
+
+  lq_etxfpm_linktypes,
+  ARRAYSIZE(lq_etxfpm_linktypes),
 
   sizeof(struct lq_etxfpm_tc_edge),
   sizeof(struct lq_etxfpm_tc_mpr_addr),
@@ -350,52 +360,35 @@ lq_etxfpm_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *edge)
   pkt_ignore_u16(curr);
 }
 
-static char *
-lq_etxfpm_print_lq(struct lq_etxfpm_linkquality *lq, char separator, struct lqtextbuffer *buffer)
-{
-  int i = 0;
-
-  if (lq->valueLq == 255) {
-    strcpy(buffer->buf, "1.000");
-    i += 5;
-  } else {
-    i = sprintf(buffer->buf, "0.%03d", (lq->valueLq * 1000) / 255);
-  }
-  buffer->buf[i++] = separator;
-
-  if (lq->valueNlq == 255) {
-    strcpy(&buffer->buf[i], "1.000");
-  } else {
-    sprintf(&buffer->buf[i], "0.%03d", (lq->valueNlq * 1000) / 255);
-  }
-  return buffer->buf;
-}
-
-static char *
-lq_etxfpm_print_link_entry_lq(struct link_entry *link, char separator, struct lqtextbuffer *buffer)
-{
+static int lq_etxfpm_get_linkentry_data(struct link_entry *link, int idx) {
   struct lq_etxfpm_link_entry *lq_link = (struct lq_etxfpm_link_entry *)link;
 
-  return lq_etxfpm_print_lq(&lq_link->lq, separator, buffer);
+  return (idx == 1) ? lq_link->lq.valueLq : lq_link->lq.valueNlq;
 }
 
-static char *
-lq_etxfpm_print_tc_edge_entry_lq(struct tc_edge_entry *edge, char separator, struct lqtextbuffer *buffer)
+static const char *
+lq_etxfpm_print_link_entry_lq(struct link_entry *link, int idx, char *buffer, size_t bufsize)
 {
-  struct lq_etxfpm_tc_edge *lq_edge = (struct lq_etxfpm_tc_edge *)edge;
+  struct lq_etxfpm_link_entry *lq_link = (struct lq_etxfpm_link_entry *)link;
 
-  return lq_etxfpm_print_lq(&lq_edge->lq, separator, buffer);
+  uint8_t value = (idx == 1) ? lq_link->lq.valueLq : lq_link->lq.valueNlq;
+  if (value == 255) {
+    strscpy(buffer, "1.000", bufsize);
+  } else {
+    snprintf(buffer, bufsize, "0.%03d", (value * 1000) / 255);
+  }
+  return buffer;
 }
 
-static char *
-lq_etxfpm_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer)
+static const char *
+lq_etxfpm_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize)
 {
   // must calculate
   uint32_t roundDown = cost >> 16;
   uint32_t fraction = ((cost & 0xffff) * 1000) >> 16;
 
-  sprintf(buffer->buf, "%u.%03u", roundDown, fraction);
-  return buffer->buf;
+  snprintf(buffer, bufsize, "%u.%03u", roundDown, fraction);
+  return buffer;
 }
 
 /*
index 48c530b..519d4a5 100644 (file)
@@ -80,11 +80,14 @@ static int lq_rfc_serialize_tc_lq(unsigned char *buff, struct tc_mpr_addr *lq);
 static void lq_rfc_deserialize_hello_lq(uint8_t const **curr, struct lq_hello_neighbor *lq);
 static void lq_rfc_deserialize_tc_lq(uint8_t const **curr, struct tc_edge_entry *lq);
 
-static char *lq_rfc_print_link_entry_lq(struct link_entry *entry, char separator, struct lqtextbuffer *buffer);
-static char *lq_rfc_print_tc_edge_entry_lq(struct tc_edge_entry *ptr, char separator, struct lqtextbuffer *buffer);
-static char *lq_rfc_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer);
+static const char *lq_rfc_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize);
+static const char *lq_rfc_print_link_entry_lq(struct link_entry *entry, int idx, char *buffer, size_t bufsize);
 
 /* RFC "lq" handler (hopcount metric with hysteresis) */
+struct lq_linkdata_type lq_rfc_linktypes[] = {
+  { "Hops", 3, 1, 4, 8, 255 }
+};
+
 struct lq_handler lq_rfc_handler = {
   "rfc",
 
@@ -115,9 +118,12 @@ struct lq_handler lq_rfc_handler = {
   &lq_rfc_deserialize_hello_lq,
   &lq_rfc_deserialize_tc_lq,
 
-  &lq_rfc_print_link_entry_lq,
-  &lq_rfc_print_tc_edge_entry_lq,
+  NULL,
   &lq_rfc_print_cost,
+  &lq_rfc_print_link_entry_lq,
+
+  lq_rfc_linktypes,
+  ARRAYSIZE(lq_rfc_linktypes),
 
   sizeof(struct tc_edge_entry),
   sizeof(struct tc_mpr_addr),
@@ -259,27 +265,19 @@ lq_rfc_deserialize_tc_lq(uint8_t const __attribute__ ((unused)) ** curr, struct
 {
 }
 
-static char *
-lq_rfc_print_link_entry_lq(struct link_entry __attribute__ ((unused)) * link, char __attribute__ ((unused)) separator,
-                           struct lqtextbuffer *buffer)
-{
-  strcpy(buffer->buf, "");
-  return buffer->buf;
-}
-
-static char *
-lq_rfc_print_tc_edge_entry_lq(struct tc_edge_entry __attribute__ ((unused)) * edge,
-                              char __attribute__ ((unused)) separator, struct lqtextbuffer *buffer)
+static const char *
+lq_rfc_print_link_entry_lq(struct link_entry __attribute__ ((unused)) * link,
+    int __attribute__ ((unused)) idx, char *buffer, size_t __attribute__ ((unused)) bufsize)
 {
-  strcpy(buffer->buf, "");
-  return buffer->buf;
+  buffer[0] = 0;
+  return buffer;
 }
 
-static char *
-lq_rfc_print_cost(olsr_linkcost cost, struct lqtextbuffer *buffer)
+static const char *
+lq_rfc_print_cost(olsr_linkcost cost, char *buffer, size_t bufsize)
 {
-  sprintf(buffer->buf, "%d", cost);
-  return buffer->buf;
+  snprintf(buffer, bufsize, "%3d", cost);
+  return buffer;
 }
 
 /*
index 1c5fa7c..bc5e9ff 100644 (file)
@@ -169,28 +169,27 @@ mapwrite_work(FILE * fmap)
       char *lla = lookup_position_latlon(&tc->addr);
       char *llb = lookup_position_latlon(&tc_edge->T_dest_addr);
       if (NULL != lla && NULL != llb) {
-        struct lqtextbuffer lqbuffer, lqbuffer2;
+        char lqbuffer[LQTEXT_MAXLENGTH];
 
         /*
          * To speed up processing, Links with both positions are named PLink()
          */
-        if (0 > fprintf(fmap, "PLink('%s','%s',%s,%s,%s,%s);\n",
+        if (0 > fprintf(fmap, "PLink('%s','%s',%s,%s,%s);\n",
                         olsr_ip_to_string(&strbuf1, &tc_edge->T_dest_addr),
                         olsr_ip_to_string(&strbuf2, &tc->addr),
-                        get_tc_edge_entry_text(tc_edge, ',', &lqbuffer2),
-                        get_linkcost_text(tc_edge->cost, false, &lqbuffer), lla, llb)) {
+                        olsr_get_linkcost_text(tc_edge->cost, false, lqbuffer, sizeof(lqbuffer)), lla, llb)) {
           return;
         }
       } else {
-        struct lqtextbuffer lqbuffer, lqbuffer2;
+        char lqbuffer[LQTEXT_MAXLENGTH];
 
         /*
          * If one link end pos is unkown, only send Link()
          */
-        if (0 > fprintf(fmap, "Link('%s','%s',%s,%s);\n",
+        if (0 > fprintf(fmap, "Link('%s','%s',%s);\n",
                         olsr_ip_to_string(&strbuf1, &tc_edge->T_dest_addr),
                         olsr_ip_to_string(&strbuf2, &tc->addr),
-                        get_tc_edge_entry_text(tc_edge, ',', &lqbuffer2), get_linkcost_text(tc_edge->cost, false, &lqbuffer))) {
+                        olsr_get_linkcost_text(tc_edge->cost, false, lqbuffer, sizeof(lqbuffer)))) {
           return;
         }
       }
index d006242..2138585 100644 (file)
@@ -1309,14 +1309,14 @@ select_best_nameserver(struct rt_entry **rt)
     if (!rt2 || olsr_cmp_rt(rt1, rt2)) {
 #if !defined REMOVE_LOG_DEBUG
       struct ipaddr_str strbuf;
-      struct lqtextbuffer lqbuffer;
+      char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
       /*
        * first is better, swap the pointers.
        */
       OLSR_DEBUG(LOG_PLUGINS, "NAME PLUGIN: nameserver %s, cost %s\n",
                  olsr_ip_to_string(&strbuf, &rt1->rt_dst.prefix),
-                 get_linkcost_text(rt1->rt_best->rtp_metric.cost, true, &lqbuffer));
+                 olsr_get_linkcost_text(rt1->rt_best->rtp_metric.cost, true, lqbuffer, sizeof(lqbuffer)));
 
       rt[nameserver_idx] = rt2;
       rt[nameserver_idx + 1] = rt1;
@@ -1356,7 +1356,7 @@ write_resolv_file(void)
       for (name = entry->names; name != NULL; name = name->next) {
 #if !defined REMOVE_LOG_DEBUG
         struct ipaddr_str strbuf;
-        struct lqtextbuffer lqbuffer;
+        char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
         route = olsr_lookup_routing_table(&name->ip);
 
@@ -1369,7 +1369,8 @@ write_resolv_file(void)
         /* enqueue it on the head of list */
         *nameserver_routes = route;
         OLSR_DEBUG(LOG_PLUGINS, "NAME PLUGIN: found nameserver %s, cost %s",
-                   olsr_ip_to_string(&strbuf, &name->ip), get_linkcost_text(route->rt_best->rtp_metric.cost, true, &lqbuffer));
+                   olsr_ip_to_string(&strbuf, &name->ip),
+                   olsr_get_linkcost_text(route->rt_best->rtp_metric.cost, true, lqbuffer, sizeof(lqbuffer)));
 
         /* find the closet one */
         select_best_nameserver(nameserver_routes);
index 96fee36..1bea32d 100644 (file)
@@ -54,6 +54,7 @@
 #include "olsr_ip_prefix_list.h"
 #include "parser.h"
 #include "olsr_comport_txt.h"
+#include "common/string.h"
 #include "common/autobuf.h"
 #include "plugin_loader.h"
 #include "plugin_util.h"
 #define PLUGIN_AUTHOR   "Henning Rogge"
 
 
-struct debuginfo_cmd {
+struct txtinfo_cmd {
   const char *name;
   olsr_txthandler handler;
-  struct olsr_txtcommand *normal, *csv;
+  struct olsr_txtcommand *cmd;
 };
 
 static bool txtinfo_pre_init(void);
@@ -79,7 +80,6 @@ static enum olsr_txtcommand_result txtinfo_topology(struct comport_connection *c
 static enum olsr_txtcommand_result txtinfo_hna(struct comport_connection *con,  char *cmd, char *param);
 static enum olsr_txtcommand_result txtinfo_mid(struct comport_connection *con,  char *cmd, char *param);
 
-
 /* plugin configuration */
 static struct ip_acl allowed_nets;
 
@@ -94,13 +94,103 @@ static const struct olsrd_plugin_parameters plugin_parameters[] = {
 DEFINE_PLUGIN6(PLUGIN_DESCR, PLUGIN_AUTHOR, txtinfo_pre_init, txtinfo_post_init, txtinfo_pre_cleanup, NULL, true, plugin_parameters)
 
 /* command callbacks and names */
-static struct debuginfo_cmd commands[] = {
-    {"link", &txtinfo_link, NULL, NULL},
-    {"neigh", &txtinfo_neigh, NULL, NULL},
-    {"topology", &txtinfo_topology, NULL, NULL},
-    {"hna", &txtinfo_hna, NULL, NULL},
-    {"mid", &txtinfo_mid, NULL, NULL},
-    {"routes", &txtinfo_routes, NULL, NULL},
+static struct txtinfo_cmd commands[] = {
+    {"link", &txtinfo_link, NULL},
+    {"neigh", &txtinfo_neigh, NULL},
+    {"topology", &txtinfo_topology, NULL},
+    {"hna", &txtinfo_hna, NULL},
+    {"mid", &txtinfo_mid, NULL},
+    {"routes", &txtinfo_routes, NULL},
+};
+
+/* constants and static storage for template engine */
+static const char KEY_LOCALIP[] = "localip";
+static const char KEY_NEIGHIP[] = "neighip";
+static const char KEY_ALIASIP[] = "aliasip";
+static const char KEY_DESTPREFIX[] = "destprefix";
+static const char KEY_SYM[] = "issym";
+static const char KEY_MPR[] = "ismpr";
+static const char KEY_MPRS[] = "ismprs";
+static const char KEY_VIRTUAL[] = "isvirtual";
+static const char KEY_WILLINGNESS[] = "will";
+static const char KEY_2HOP[] = "2hop";
+static const char KEY_LINKCOST[] = "linkcost";
+static const char KEY_RAWLINKCOST[] = "rawlinkcost";
+static const char KEY_COMMONCOST[] = "commoncost";
+static const char KEY_RAWCOMMONCOST[] = "rawcommoncost";
+static const char KEY_HOPCOUNT[] = "hopcount";
+static const char KEY_INTERFACE[] = "interface";
+static const char KEY_VTIME[] = "vtime";
+
+static struct ipaddr_str buf_localip, buf_neighip, buf_aliasip;
+struct ipprefix_str buf_destprefix;
+static char buf_sym[6], buf_mrp[4], buf_mprs[4], buf_virtual[4];
+static char buf_willingness[7];
+static char buf_2hop[6];
+static char buf_rawlinkcost[11], buf_rawcommoncost[11];
+static char buf_linkcost[LQTEXT_MAXLENGTH], buf_commoncost[LQTEXT_MAXLENGTH];
+static char buf_hopcount[4];
+static char buf_interface[IF_NAMESIZE];
+struct millitxt_buf buf_vtime;
+
+static size_t tmpl_indices[32];
+
+/* a link metric may contain up to 8 values */
+static const char *keys_link[] = {
+  KEY_LOCALIP, KEY_NEIGHIP, KEY_SYM, KEY_MPR, KEY_VTIME,
+  KEY_RAWLINKCOST, KEY_LINKCOST,
+  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+static char *values_link[] = {
+  buf_localip.buf, buf_neighip.buf, buf_sym, buf_mrp, buf_vtime.buf,
+  buf_rawlinkcost, buf_linkcost,
+  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+static char tmpl_link[256], headline_link[256];
+static size_t link_keys_static = 0, link_keys_count = 0, link_value_size = 0;
+
+static const char *tmpl_neigh = "%neighip%\t%issym%\t%ismpr%\t%ismprs%\t%will%\t%2hop%\n";
+static const char *keys_neigh[] = {
+  KEY_NEIGHIP, KEY_SYM, KEY_MPR, KEY_MPRS, KEY_WILLINGNESS, KEY_2HOP
+};
+static char *values_neigh[] = {
+  buf_neighip.buf, buf_sym, buf_mprs, buf_mprs, buf_willingness, buf_2hop
+};
+
+static const char *tmpl_routes = "%destprefix%\t%neighip%\t%hopcount%\t%linkcost%\t%interface%\n";
+static const char *keys_routes[] = {
+  KEY_DESTPREFIX, KEY_NEIGHIP, KEY_HOPCOUNT, KEY_VTIME,
+  KEY_INTERFACE, KEY_RAWLINKCOST, KEY_LINKCOST
+};
+static char *values_routes[] = {
+  buf_destprefix.buf, buf_neighip.buf, buf_hopcount, buf_vtime.buf,
+  buf_interface, buf_rawlinkcost, buf_linkcost
+};
+
+static const char *tmpl_topology = "%neighip%\t%localip%\t%isvirtual%\t%linkcost%\t%commoncost%\n";
+static const char *keys_topology[] = {
+  KEY_LOCALIP, KEY_NEIGHIP, KEY_VIRTUAL, KEY_VTIME,
+  KEY_RAWLINKCOST, KEY_LINKCOST, KEY_RAWCOMMONCOST, KEY_COMMONCOST
+};
+static char *values_topology[] = {
+  buf_localip.buf, buf_neighip.buf, buf_virtual, buf_vtime.buf,
+  buf_rawlinkcost, buf_linkcost, buf_rawcommoncost, buf_commoncost
+};
+
+static const char *tmpl_hna = "%localip%\t%destprefix%\t%vtime%\n";
+static const char *keys_hna[] = {
+  KEY_LOCALIP, KEY_DESTPREFIX, KEY_VTIME
+};
+static char *values_hna[] = {
+  buf_localip.buf, buf_destprefix.buf, buf_vtime.buf
+};
+
+static const char *tmpl_mid = "%localip%\t%aliasip%\t%vtime%\n";
+static const char *keys_mid[] = {
+  KEY_LOCALIP, KEY_ALIASIP, KEY_VTIME
+};
+static char *values_mid[] = {
+  buf_localip.buf, buf_aliasip.buf, buf_vtime.buf
 };
 
 /**
@@ -133,8 +223,7 @@ txtinfo_pre_cleanup(void)
   size_t i;
 
   for (i=0; i<ARRAYSIZE(commands); i++) {
-    olsr_com_remove_normal_txtcommand(commands[i].normal);
-    olsr_com_remove_csv_txtcommand(commands[i].csv);
+    olsr_com_remove_normal_txtcommand(commands[i].cmd);
   }
   ip_acl_flush(&allowed_nets);
   return false;
@@ -148,11 +237,41 @@ txtinfo_post_init(void)
 {
   size_t i;
 
+  /* count static link keys */
+  while (keys_link[link_keys_static]) {
+    link_keys_static++;
+    link_keys_count++;
+  }
+
+  /* generate dynamic link keys */
+  for (i=1; i<olsr_get_linklabel_count(); i++) {
+    keys_link[link_keys_static + i - 1] = olsr_get_linklabel(i);
+    values_link[link_keys_static + i - 1] = olsr_malloc(LQTEXT_MAXLENGTH, "txtinfo linktemplate values");
+    link_keys_count++;
+  }
+  link_value_size = LQTEXT_MAXLENGTH;
+
+  /* generate link template */
+  strscpy(tmpl_link, "%localip%\t%neighip", sizeof(tmpl_link));
+  for (i=1; i<olsr_get_linklabel_count(); i++) {
+    strscat(tmpl_link, "%\t%", sizeof(tmpl_link));
+    strscat(tmpl_link, olsr_get_linklabel(i), sizeof(tmpl_link));
+  }
+  strscat(tmpl_link, "%\t%linkcost%\n", sizeof(tmpl_link));
+
+  /* generate link summary */
+  strscpy(headline_link, "Table: Links\nLocal IP\tRemote IP", sizeof(headline_link));
+  for (i=1; i<olsr_get_linklabel_count(); i++) {
+    strscat(headline_link, "\t", sizeof(headline_link));
+    strscat(headline_link, olsr_get_linklabel(i), sizeof(headline_link));
+  }
+  strscat(headline_link, "\t", sizeof(headline_link));
+  strscat(headline_link, olsr_get_linklabel(0), sizeof(headline_link));
+  strscat(headline_link, "\n", sizeof(headline_link));
+
   for (i=0; i<ARRAYSIZE(commands); i++) {
-    commands[i].normal = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
-    commands[i].csv = olsr_com_add_csv_txtcommand(commands[i].name, commands[i].handler);
-    commands[i].normal->acl = &allowed_nets;
-    commands[i].csv->acl = &allowed_nets;
+    commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
+    commands[i].cmd->acl = &allowed_nets;
   }
   return false;
 }
@@ -161,22 +280,33 @@ txtinfo_post_init(void)
  * Callback for neigh command
  */
 static enum olsr_txtcommand_result
-txtinfo_neigh(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused)))
+txtinfo_neigh(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param)
 {
   struct nbr_entry *neigh;
-  if (!con->is_csv && abuf_puts(&con->out, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
+  const char *template;
+  int indexLength;
+
+  template = param != NULL ? param : tmpl_neigh;
+  if (param == NULL &&
+      abuf_puts(&con->out, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
+    return ABUF_ERROR;
+  }
+
+  if ((indexLength = abuf_template_init(keys_neigh, ARRAYSIZE(keys_neigh), template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
     return ABUF_ERROR;
   }
 
   /* Neighbors */
   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
-    struct ipaddr_str buf1;
-    if (abuf_appendf(&con->out, !con->is_csv ? "%s\t%s\t%s\t%s\t%d\t%d\n" : "neigh,%s,%s,%s,%s,%d,%d\n",
-                       olsr_ip_to_string(&buf1, &neigh->nbr_addr),
-                       neigh->is_sym ? "YES" : "NO",
-                       neigh->is_mpr ? "YES" : "NO",
-                       neigh->mprs_count > 0 ? "YES" : "NO",
-                       neigh->willingness, neigh->con_tree.count) < 0) {
+    olsr_ip_to_string(&buf_neighip, &neigh->nbr_addr);
+    strscpy(buf_sym, neigh->is_sym ? OLSR_YES : OLSR_NO, sizeof(buf_sym));
+    strscpy(buf_mrp, neigh->is_mpr ? OLSR_YES : OLSR_NO, sizeof(buf_mrp));
+    strscpy(buf_mprs, neigh->mprs_count>0 ? OLSR_YES : OLSR_NO, sizeof(buf_mprs));
+
+    snprintf(buf_willingness, sizeof(buf_willingness), "%d", neigh->willingness);
+    snprintf(buf_2hop, sizeof(buf_2hop), "%d", neigh->con_tree.count);
+
+    if (abuf_templatef(&con->out, template, values_neigh, tmpl_indices, indexLength) < 0) {
         return ABUF_ERROR;
     }
   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
@@ -184,28 +314,55 @@ txtinfo_neigh(struct comport_connection *con,  char *cmd __attribute__ ((unused)
   return CONTINUE;
 }
 
+#if 0
+static char tmpl_link[256], link_template_csv[256];
+static const char *keys_link[4+16] = {
+  "localip",
+  "neighip",
+  "rawlinkcost",
+  "linkcost",
+  NULL
+};
+static size_t link_keys_static = 0, link_keys_count = 0;
+#endif
 /**
  * Callback for link command
  */
 static enum olsr_txtcommand_result
-txtinfo_link(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused)))
+txtinfo_link(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param)
 {
   struct link_entry *lnk;
+  size_t i;
+  const char *template;
+  int indexLength;
+
+  template = param != NULL ? param : tmpl_link;
+  if (param == NULL) {
+    if (abuf_puts(&con->out, headline_link) < 0) {
+      return ABUF_ERROR;
+    }
+  }
 
-  OLSR_DEBUG(LOG_NETWORKING, "Starting 'link' command...\n");
-  if (!con->is_csv && abuf_puts(&con->out, "Table: Links\nLocal IP\tRemote IP\tLQ\tNLQ\tCost\n") < 0) {
+  if ((indexLength = abuf_template_init(keys_link, link_keys_count,
+      template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
     return ABUF_ERROR;
   }
 
   /* Link set */
   OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
-    struct ipaddr_str buf1, buf2;
-    struct lqtextbuffer lqbuffer1, lqbuffer2;
-    if (abuf_appendf(&con->out,
-                     !con->is_csv ? "%s\t%s\t%s\t%s\t\n" : "link,%s,%s,%s,%s\n",
-                     olsr_ip_to_string(&buf1, &lnk->local_iface_addr),
-                     olsr_ip_to_string(&buf2, &lnk->neighbor_iface_addr),
-                     get_link_entry_text(lnk, '\t', &lqbuffer1), get_linkcost_text(lnk->linkcost, false, &lqbuffer2)) < 0) {
+    olsr_ip_to_string(&buf_localip, &lnk->local_iface_addr);
+    olsr_ip_to_string(&buf_neighip, &lnk->neighbor_iface_addr);
+    strscpy(buf_sym, lnk->status == SYM_LINK ? OLSR_YES : OLSR_NO, sizeof(buf_sym));
+    strscpy(buf_mrp, lnk->is_mpr ? OLSR_YES : OLSR_NO, sizeof(buf_mrp));
+    olsr_milli_to_txt(&buf_vtime, lnk->link_sym_timer->timer_clock - now_times);
+    snprintf(buf_rawlinkcost, sizeof(buf_rawlinkcost), "%ud", lnk->linkcost);
+
+    olsr_get_linkcost_text(lnk->linkcost, false, buf_linkcost, sizeof(buf_linkcost));
+    for (i=1; i< olsr_get_linklabel_count(); i++) {
+      olsr_get_linkdata_text(lnk, i, values_link[link_keys_static + i - 1], link_value_size);
+    }
+
+    if (abuf_templatef(&con->out, template, values_link, tmpl_indices, indexLength) < 0) {
         return ABUF_ERROR;
     }
   } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk);
@@ -220,23 +377,35 @@ static enum olsr_txtcommand_result
 txtinfo_routes(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused)))
 {
   struct rt_entry *rt;
+  const char *template;
+  int indexLength;
+
+  template = param != NULL ? param : tmpl_routes;
+  if (param == NULL) {
+    if (abuf_appendf(&con->out, "Table: Routes\nDestination\tGateway IP\tMetric\t%s\tInterface\n",
+        olsr_get_linklabel(0)) < 0) {
+      return ABUF_ERROR;
+    }
+  }
 
-  if (!con->is_csv && abuf_puts(&con->out, "Table: Routes\nDestination\tGateway IP\tMetric\tETX\tInterface\n") < 0) {
+  if ((indexLength = abuf_template_init(keys_routes, ARRAYSIZE(keys_routes),
+      template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
     return ABUF_ERROR;
   }
 
   /* Walk the route table */
   OLSR_FOR_ALL_RT_ENTRIES(rt) {
-    struct ipaddr_str ipbuf;
-    struct ipprefix_str prefixstr;
-    struct lqtextbuffer lqbuffer;
-    if (abuf_appendf(&con->out, !con->is_csv ? "%s\t%s\t%u\t%s\t%s\t\n" : "route,%s,%s,%u,%s,%s\n",
-                     olsr_ip_prefix_to_string(&prefixstr, &rt->rt_dst),
-                     olsr_ip_to_string(&ipbuf, &rt->rt_best->rtp_nexthop.gateway),
-                     rt->rt_best->rtp_metric.hops,
-                     get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer),
-                     rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]") < 0) {
-      return ABUF_ERROR;
+    olsr_ip_prefix_to_string(&buf_destprefix, &rt->rt_dst);
+    olsr_ip_to_string(&buf_neighip, &rt->rt_best->rtp_nexthop.gateway);
+    snprintf(buf_hopcount, sizeof(buf_hopcount), "%d", rt->rt_best->rtp_metric.hops);
+    snprintf(buf_rawlinkcost, sizeof(buf_rawlinkcost), "%ud", rt->rt_best->rtp_metric.cost);
+    olsr_get_linkcost_text(rt->rt_best->rtp_metric.cost, true, buf_linkcost, sizeof(buf_linkcost));
+    strscpy(buf_interface,
+        rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]",
+        sizeof(buf_interface));
+
+    if (abuf_templatef(&con->out, template, values_routes, tmpl_indices, indexLength) < 0) {
+        return ABUF_ERROR;
     }
   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
   return CONTINUE;
@@ -249,24 +418,51 @@ static enum olsr_txtcommand_result
 txtinfo_topology(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused)))
 {
   struct tc_entry *tc;
-  if (!con->is_csv && abuf_puts(&con->out, "Table: Topology\nDest. IP\tLast hop IP\tLQ\tNLQ\tCost\n") < 0) {
+  const char *template;
+  int indexLength;
+
+  template = param != NULL ? param : tmpl_topology;
+  if (param == NULL) {
+    if (abuf_appendf(&con->out, "Table: Topology\nDest. IP\tLast hop IP\tVirtual\t%s\t(common)\n",
+        olsr_get_linklabel(0)) < 0) {
+      return ABUF_ERROR;
+    }
+  }
+
+  if ((indexLength = abuf_template_init(keys_topology, ARRAYSIZE(keys_topology),
+      template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
     return ABUF_ERROR;
   }
 
   /* Topology */
   OLSR_FOR_ALL_TC_ENTRIES(tc) {
     struct tc_edge_entry *tc_edge;
+    olsr_ip_to_string(&buf_localip, &tc->addr);
+    if (tc->validity_timer) {
+      olsr_milli_to_txt(&buf_vtime, tc->validity_timer->timer_clock - now_times);
+    }
+    else {
+      strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
+    }
+
     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
-      if (tc_edge->edge_inv) {
-        struct ipaddr_str dstbuf, addrbuf;
-        struct lqtextbuffer lqbuffer1, lqbuffer2;
-        if (abuf_appendf(&con->out, !con->is_csv ? "%s\t%s\t%s\t%s\n" : "topo,%s,%s,%s,%s\n",
-                         olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
-                         olsr_ip_to_string(&addrbuf, &tc->addr),
-                         get_tc_edge_entry_text(tc_edge, '\t', &lqbuffer1),
-                         get_linkcost_text(tc_edge->cost, false, &lqbuffer2)) < 0) {
+      olsr_ip_to_string(&buf_neighip, &tc_edge->T_dest_addr);
+      strscpy(buf_virtual, tc_edge->is_virtual ? OLSR_YES : OLSR_NO, sizeof(buf_virtual));
+      if (tc_edge->is_virtual) {
+        buf_linkcost[0] = 0;
+        buf_rawlinkcost[0] = '0';
+        buf_rawlinkcost[1] = 0;
+      }
+      else {
+        snprintf(buf_rawlinkcost, sizeof(buf_rawlinkcost), "%ud", tc_edge->cost);
+        olsr_get_linkcost_text(tc_edge->cost, false, buf_linkcost, sizeof(buf_linkcost));
+      }
+
+      snprintf(buf_rawcommoncost, sizeof(buf_rawcommoncost), "%ud", tc_edge->common_cost);
+      olsr_get_linkcost_text(tc_edge->common_cost, false, buf_commoncost, sizeof(buf_commoncost));
+
+      if (abuf_templatef(&con->out, template, values_topology, tmpl_indices, indexLength) < 0) {
           return ABUF_ERROR;
-        }
       }
     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
   } OLSR_FOR_ALL_TC_ENTRIES_END(tc)
@@ -274,17 +470,6 @@ txtinfo_topology(struct comport_connection *con,  char *cmd __attribute__ ((unus
   return CONTINUE;
 }
 
-/**
- * helper which prints an HNA entry
- */
-static INLINE bool
-txtinfo_print_hna_entry(struct autobuf *buf, const char *format, const struct olsr_ip_prefix *hna_prefix, const union olsr_ip_addr *ipaddr)
-{
-  struct ipaddr_str mainaddrbuf;
-  struct ipprefix_str addrbuf;
-  return abuf_appendf(buf, format, olsr_ip_prefix_to_string(&addrbuf, hna_prefix), olsr_ip_to_string(&mainaddrbuf, ipaddr)) < 0;
-}
-
 /**
  * Callback for hna command
  */
@@ -293,27 +478,45 @@ txtinfo_hna(struct comport_connection *con,  char *cmd __attribute__ ((unused)),
 {
   const struct ip_prefix_entry *hna;
   struct tc_entry *tc;
+  const char *template;
+  int indexLength;
+
+  template = param != NULL ? param : tmpl_hna;
+  if (param == NULL) {
+    if (abuf_puts(&con->out, "Table: HNA\nDestination\tGateway\tvtime\n") < 0) {
+      return ABUF_ERROR;
+    }
+  }
 
-  const char *format = !con->is_csv ? "%s\t%s\n" : "hna,%s,%s\n";
-  if (!con->is_csv && abuf_puts(&con->out, "Table: HNA\nDestination\tGateway\n") < 0) {
+  if ((indexLength = abuf_template_init(keys_hna, ARRAYSIZE(keys_hna),
+      template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
     return ABUF_ERROR;
   }
 
   /* Announced HNA entries */
   OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
-    if (txtinfo_print_hna_entry(&con->out, format, &hna->net, &olsr_cnf->router_id)) {
-      return ABUF_ERROR;
+    olsr_ip_to_string(&buf_localip, &olsr_cnf->router_id);
+    olsr_ip_prefix_to_string(&buf_destprefix, &hna->net);
+    strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
+
+    if (abuf_templatef(&con->out, template, values_hna, tmpl_indices, indexLength) < 0) {
+        return ABUF_ERROR;
     }
   }
   OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
-
-    /* HNA entries */
-    OLSR_FOR_ALL_TC_ENTRIES(tc) {
+  /* HNA entries */
+  OLSR_FOR_ALL_TC_ENTRIES(tc) {
     struct hna_net *tmp_net;
+
+    olsr_ip_to_string(&buf_localip, &olsr_cnf->router_id);
+    olsr_milli_to_txt(&buf_vtime, tc->validity_timer->timer_clock - now_times);
+
     /* Check all networks */
     OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
-      if (txtinfo_print_hna_entry(&con->out, format, &tmp_net->hna_prefix, &tc->addr)) {
-        return ABUF_ERROR;
+      olsr_ip_prefix_to_string(&buf_destprefix, &tmp_net->hna_prefix);
+
+      if (abuf_templatef(&con->out, template, values_hna, tmpl_indices, indexLength) < 0) {
+          return ABUF_ERROR;
       }
     } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_net);
   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
@@ -328,30 +531,51 @@ static enum olsr_txtcommand_result
 txtinfo_mid(struct comport_connection *con,  char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused)))
 {
   struct tc_entry *tc;
-  const char *prefix = !con->is_csv ? "" : "mid,";
-  const char sep = !con->is_csv ? '\t' : ',';
+  struct interface *interface;
 
-  if (!con->is_csv && abuf_puts(&con->out, "Table: MID\nIP address\tAliases\n") < 0) {
+  const char *template;
+  int indexLength;
+
+  template = param != NULL ? param : tmpl_mid;
+  if (param == NULL) {
+    if (abuf_puts(&con->out, "Table: MID\nIP address\tAliases\tvtime\n") < 0) {
+      return ABUF_ERROR;
+    }
+  }
+
+  if ((indexLength = abuf_template_init(keys_mid, ARRAYSIZE(keys_mid),
+      template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
     return ABUF_ERROR;
   }
 
+  OLSR_FOR_ALL_INTERFACES(interface) {
+    if (olsr_ipcmp(&olsr_cnf->router_id, &interface->ip_addr) != 0) {
+      olsr_ip_to_string(&buf_localip, &olsr_cnf->router_id);
+      olsr_ip_to_string(&buf_aliasip, &interface->ip_addr);
+      strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
+
+      if (abuf_templatef(&con->out, template, values_mid, tmpl_indices, indexLength) < 0) {
+          return ABUF_ERROR;
+      }
+    }
+  } OLSR_FOR_ALL_INTERFACES_END(interface)
+
   /* MID root is the TC entry */
   OLSR_FOR_ALL_TC_ENTRIES(tc) {
-    struct ipaddr_str ipbuf;
     struct mid_entry *alias;
 
-    if (abuf_appendf(&con->out, "%s%s", prefix, olsr_ip_to_string(&ipbuf, &tc->addr)) < 0) {
-      return ABUF_ERROR;
-    }
+    olsr_ip_to_string(&buf_localip, &tc->addr);
+    if (tc->validity_timer) {
+      olsr_milli_to_txt(&buf_vtime, tc->validity_timer->timer_clock - now_times);
 
-    OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
-      if (abuf_appendf(&con->out, "%c%s", sep, olsr_ip_to_string(&ipbuf, &alias->mid_alias_addr)) < 0) {
-        return ABUF_ERROR;
+      OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias) {
+        olsr_ip_to_string(&buf_aliasip, &alias->mid_alias_addr);
+
+        if (abuf_templatef(&con->out, template, values_mid, tmpl_indices, indexLength) < 0) {
+          return ABUF_ERROR;
+        }
       }
-    }
-    OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
-    if (abuf_appendf(&con->out, "\n") < 0) {
-      return ABUF_ERROR;
+      OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, alias);
     }
   } OLSR_FOR_ALL_TC_ENTRIES_END(tc)
   return CONTINUE;
index e41d654..c3bc0a1 100644 (file)
@@ -211,6 +211,78 @@ abuf_pull(struct autobuf * autobuf, int len) {
   autobuf->size = newsize;
   return 0;
 }
+
+static int
+abuf_find_template(const char **keys, int tmplLength, const char *txt, int txtLength) {
+  int i;
+
+  for (i=0; i<tmplLength; i++) {
+    if (strncmp(keys[i], txt, txtLength) == 0 && keys[i][txtLength] == 0) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+int
+abuf_template_init (const char **keys, size_t tmplLength, const char *format, size_t *indexTable, size_t indexLength) {
+  size_t pos = 0, indexCount = 0;
+  int start = -1, i = 0;
+
+  while (format[pos]) {
+    if (format[pos] == '%') {
+      if (start == -1) {
+        start = pos++;
+        continue;
+      }
+      if (pos - start > 1) {
+        if (indexCount + 3 > indexLength) {
+          return -1;
+        }
+
+        i = abuf_find_template(keys, tmplLength, &format[start+1], pos-start-1);
+        if (i != -1) {
+          /* value index */
+          indexTable[indexCount++] = i;
+
+          /* start position (including) */
+          indexTable[indexCount++] = start;
+
+          /* end position (excluding) */
+          indexTable[indexCount++] = pos+1;
+        }
+      }
+      start = -1;
+    }
+    pos++;
+  }
+  return indexCount;
+}
+
+int abuf_templatef (struct autobuf *buf, const char *format, char **values, size_t *table, size_t indexCount) {
+  size_t i, last = 0;
+
+  for (i=0; i<indexCount; i+=3) {
+    /* copy praefix text */
+    if (last < table[i+1]) {
+      if (abuf_memcpy(buf, &format[last], table[i+1] - last) < 0) {
+        return -1;
+      }
+    }
+    if (abuf_puts(buf, values[table[i]]) < 0) {
+      return -1;
+    }
+    last = table[i+2];
+  }
+
+  if (last < strlen(format)) {
+    if (abuf_puts(buf, &format[last]) < 0) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
 /*
  * Local Variables:
  * mode: c
index 6791b07..6f0e133 100644 (file)
@@ -62,6 +62,8 @@ int EXPORT(abuf_strftime) (struct autobuf * autobuf, const char *format, const s
 int EXPORT(abuf_memcpy) (struct autobuf * autobuf, const void *p, const unsigned int len);
 int EXPORT(abuf_memcpy_prefix) (struct autobuf *autobuf, const void *p, const unsigned int len);
 int EXPORT(abuf_pull) (struct autobuf * autobuf, int len);
+int EXPORT(abuf_template_init) (const char **keys, size_t length, const char *format, size_t *indexTable, size_t indexLength);
+int EXPORT(abuf_templatef) (struct autobuf *autobuf, const char *format, char **values, size_t *indexTable, size_t indexCount);
 #endif
 
 /*
index e10e677..e96d446 100644 (file)
@@ -45,6 +45,9 @@
 #include <string.h>
 #include <assert.h>
 
+const char *OLSR_YES = "yes";
+const char *OLSR_NO = "no";
+
 /*
  * A somewhat safe version of strncpy and strncat. Note, that
  * BSD/Solaris strlcpy()/strlcat() differ in implementation, while
index e602c40..c73b143 100644 (file)
@@ -50,6 +50,9 @@ char *EXPORT(strscpy) (char *dest, const char *src, size_t size);
 
 char *EXPORT(strscat) (char *dest, const char *src, size_t size);
 
+extern const char *EXPORT(OLSR_YES);
+extern const char *EXPORT(OLSR_NO);
+
 #endif
 
 /*
index 3a706af..4359f55 100644 (file)
@@ -370,11 +370,11 @@ olsr_expire_link_sym_timer(void *context)
   link = (struct link_entry *)context;
   link->link_sym_timer = NULL;  /* be pedandic */
 
-  if (link->prev_status != SYM_LINK) {
+  if (link->status != SYM_LINK) {
     return;
   }
 
-  link->prev_status = lookup_link_status(link);
+  link->status = lookup_link_status(link);
   olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
   changes_neighborhood = true;
 }
@@ -484,7 +484,7 @@ add_link_entry(const union olsr_ip_addr *local,
   /* L_time = current time + validity time */
   olsr_set_link_timer(link, vtime);
 
-  link->prev_status = ASYM_LINK;
+  link->status = ASYM_LINK;
 
   link->loss_helloint = htime;
 
@@ -620,9 +620,9 @@ update_link_entry(const union olsr_ip_addr *local,
   entry->vtime = message->comm.vtime;
   entry->ASYM_time = GET_TIMESTAMP(message->comm.vtime);
 
-  entry->prev_status = check_link_status(message, in_if);
+  entry->status = check_link_status(message, in_if);
 
-  switch (entry->prev_status) {
+  switch (entry->status) {
   case (LOST_LINK):
     olsr_stop_timer(entry->link_sym_timer);
     entry->link_sym_timer = NULL;
@@ -724,18 +724,75 @@ olsr_print_link_set(void)
 #if !defined REMOVE_LOG_INFO
   /* The whole function makes no sense without it. */
   struct link_entry *walker;
-  const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
+  char totaltxt[256];
+  const char *txt;
+  int addrsize;
+  size_t i, j, length, max, totaltxt_len;
+  addrsize = olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+
+  /* generate LQ headline */
+  totaltxt[0] = 0;
+  totaltxt_len = 0;
+  for (i=1; i<olsr_get_linklabel_count(); i++) {
+    txt = olsr_get_linklabel(i);
+    max = olsr_get_linklabel_maxlength(i);
+
+    length = strlen(txt);
+
+    /* add seperator */
+    if (i != 1) {
+      totaltxt[totaltxt_len++] = '/';
+    }
+
+    /* reserve space for label */
+    if (max > length) {
+      for (j=0; j<max; j++) {
+        totaltxt[totaltxt_len + j] = '-';
+      }
+    }
+
+    /* copy label */
+    strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
+    totaltxt_len += max;
+  }
+  totaltxt[totaltxt_len] = 0;
 
   OLSR_INFO(LOG_LINKS, "\n--- %s ---------------------------------------------------- LINKS\n\n", olsr_wallclock_string());
-  OLSR_INFO_NH(LOG_LINKS, "%-*s  %-6s %-14s %s\n", addrsize, "IP address", "hyst", "      LQ      ", "ETX");
+  OLSR_INFO_NH(LOG_LINKS, "%-*s  %-6s %s %s\n", addrsize, "IP address", "hyst", totaltxt , olsr_get_linklabel(0));
 
   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
     struct ipaddr_str buf;
-    struct lqtextbuffer lqbuffer1, lqbuffer2;
+    char lqbuffer[LQTEXT_MAXLENGTH];
+
+    /* generate LQ headline */
+    totaltxt[0] = 0;
+    totaltxt_len = 0;
+    for (i=1; i<olsr_get_linklabel_count(); i++) {
+      txt = olsr_get_linkdata_text(walker, i, lqbuffer, sizeof(lqbuffer));
+      max = olsr_get_linklabel_maxlength(i);
 
-    OLSR_INFO_NH(LOG_LINKS, "%-*s %-14s %s\n",
+      length = strlen(txt);
+
+      /* add seperator */
+      if (i != 1) {
+        totaltxt[totaltxt_len++] = '/';
+      }
+
+      /* reserve space for label */
+      if (max > length) {
+        for (j=0; j<max; j++) {
+          totaltxt[totaltxt_len + j] = ' ';
+        }
+      }
+
+      /* copy label */
+      strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
+      totaltxt_len += max;
+    }
+    totaltxt[totaltxt_len] = 0;
+    OLSR_INFO_NH(LOG_LINKS, "%-*s %s %s\n",
                  addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
-                 get_link_entry_text(walker, '/', &lqbuffer1), get_linkcost_text(walker->linkcost, false, &lqbuffer2));
+                 totaltxt, olsr_get_linkcost_text(walker->linkcost, false, lqbuffer, sizeof(lqbuffer)));
   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
 #endif
 }
index ba6daa3..bbd7d75 100644 (file)
@@ -65,9 +65,9 @@ struct link_entry {
   uint32_t ASYM_time;
   uint32_t vtime;
   struct nbr_entry *neighbor;
-  uint8_t prev_status;
+  uint8_t status;
 
-  bool is_mprs;
+  bool is_mpr, is_mprs;
 
   /*
    * packet loss
index eab1460..0139772 100644 (file)
@@ -51,6 +51,7 @@ olsr_calculate_lq_mpr(void)
 {
   struct nbr2_entry *nbr2;
   struct nbr_con *walker;
+  struct link_entry *lnk;
   int k;
   struct nbr_entry *neigh;
   olsr_linkcost best, best_1hop;
@@ -94,7 +95,7 @@ olsr_calculate_lq_mpr(void)
        */
 
       /* determine the link quality of the direct link */
-      struct link_entry *lnk = get_best_link_to_neighbor(&neigh->nbr_addr);
+      lnk = get_best_link_to_neighbor(&neigh->nbr_addr);
       if (!lnk) {
         continue;
       }
@@ -163,6 +164,10 @@ olsr_calculate_lq_mpr(void)
       }
   } OLSR_FOR_ALL_NBR2_ENTRIES_END(nbr2);
 
+  /* ugly hack */
+  OLSR_FOR_ALL_LINK_ENTRIES(lnk) {
+    lnk->is_mpr = lnk->neighbor->is_mpr;
+  } OLSR_FOR_ALL_LINK_ENTRIES_END(lnk)
   if (mpr_changes && olsr_cnf->tc_redundancy > 0)
     signal_link_changes(true);
 }
index a7fd656..f8f7a13 100644 (file)
@@ -50,6 +50,8 @@
 #include "common/string.h"
 #include "olsr_logging.h"
 
+#include "assert.h"
+
 struct lq_handler *active_lq_handler = NULL;
 
 static struct olsr_cookie_info *tc_mpr_addr_mem_cookie = NULL;
@@ -240,67 +242,136 @@ olsr_memorize_foreign_hello_lq(struct link_entry *local, struct lq_hello_neighbo
 }
 
 /*
- * get_link_entry_text
+ * get_linkcost_text
+ *
+ * This function transforms an olsr_linkcost value into it's text representation and copies
+ * the result into a buffer.
+ *
+ * @param linkcost value
+ * @param true to transform the cost of a route, false for a link
+ * @param pointer to buffer
+ * @param size of buffer
+ * @return pointer to buffer filled with text
+ */
+const char *
+olsr_get_linkcost_text(olsr_linkcost cost, bool route, char *buffer, size_t bufsize)
+{
+  static const char *infinite = "INF";
+
+  if (route) {
+    if (cost == ROUTE_COST_BROKEN) {
+      strscpy(buffer, infinite, bufsize);
+      return buffer;
+    }
+  } else {
+    if (cost >= LINK_COST_BROKEN) {
+      strscpy(buffer, infinite, bufsize);
+      return buffer;
+    }
+  }
+  return active_lq_handler->print_cost(cost, buffer, bufsize);
+}
+
+/*
+ * olsr_get_linkdata_text
  *
- * this function returns the text representation of a link_entry cost value.
- * It's not thread save and should not be called twice with the same println
- * value in the same context (a single printf command for example).
+ * this function returns the text representation of one linkquality parameter.
  *
  * @param pointer to link_entry
- * @param char separator between LQ and NLQ
+ * @param index of linkquality parameter
  * @param buffer for output
+ * @param size of buffer
  * @return pointer to a buffer with the text representation
  */
 const char *
-get_link_entry_text(struct link_entry *entry, char separator, struct lqtextbuffer *buffer)
+olsr_get_linkdata_text(struct link_entry *entry, int idx, char *buffer, size_t bufsize)
 {
-  return active_lq_handler->print_link_entry_lq(entry, separator, buffer);
+  if (idx == 0) {
+    return olsr_get_linkcost_text(entry->linkcost, false, buffer, bufsize);
+  }
+  return active_lq_handler->print_link_entry_lq(entry, idx, buffer, bufsize);
 }
 
 /*
- * get_tc_edge_entry_text
+ * olsr_get_linklabel
  *
- * this function returns the text representation of a tc_edge_entry cost value.
- * It's not thread save and should not be called twice with the same println
- * value in the same context (a single printf command for example).
+ * this function returns the label of a linkquality parameter
  *
- * @param pointer to tc_edge_entry
- * @param char separator between LQ and NLQ
- * @param pointer to buffer
- * @return pointer to the buffer with the text representation
+ * @param index of lq parameter (0 is always "linkcost")
+ * @return pointer to static string with label
  */
 const char *
-get_tc_edge_entry_text(struct tc_edge_entry *entry, char separator, struct lqtextbuffer *buffer)
-{
-  return active_lq_handler->print_tc_edge_entry_lq(entry, separator, buffer);
+olsr_get_linklabel (int idx) {
+  assert (idx >= 0 && idx < active_lq_handler->linkdata_hello_count);
+  return active_lq_handler->linkdata_hello[idx].name;
 }
 
 /*
- * get_linkcost_text
+ * olsr_get_linklabel_maxlength
  *
- * This function transforms an olsr_linkcost value into it's text representation and copies
- * the result into a buffer.
+ * this function returns the maximum length (in characters)
+ * of a linkquality parameter value
  *
- * @param linkcost value
- * @param true to transform the cost of a route, false for a link
- * @param pointer to buffer
- * @return pointer to buffer filled with text
+ * @param index of lq parameter (0 is always "linkcost")
+ * @return number of bytes necessary to store a lq value string
  */
-const char *
-get_linkcost_text(olsr_linkcost cost, bool route, struct lqtextbuffer *buffer)
-{
-  static const char *infinite = "INFINITE";
+size_t
+olsr_get_linklabel_maxlength (int idx) {
+  assert (idx >= 0 && idx < active_lq_handler->linkdata_hello_count);
+  return active_lq_handler->linkdata_hello[idx].name_maxlen;
+}
 
-  if (route) {
-    if (cost == ROUTE_COST_BROKEN) {
-      return infinite;
+/*
+ * olsr_get_linklabel_count
+ *
+ * @return number of linkquality parameters including linkcost
+ */
+size_t olsr_get_linklabel_count (void) {
+  return active_lq_handler->linkdata_hello_count;
+}
+
+/*
+ * olsr_get_linkdata_quality
+ *
+ * This function allows you to judge the quality of a certain linkquality parameter
+ * (in the categories BEST, GOOD, AVERAGE, BAD and WORST)
+ *
+ * @param link entry
+ * @param index of linkquality parameter
+ * @return enum with linkquality estinate
+ */
+enum lq_linkdata_quality olsr_get_linkdata_quality (struct link_entry *link, int idx) {
+  struct lq_linkdata_type *linkdata;
+  int value;
+
+  assert (idx >= 0 && idx < active_lq_handler->linkdata_hello_count);
+  linkdata = &active_lq_handler->linkdata_hello[idx];
+  value = active_lq_handler->get_link_entry_data(link, idx);
+
+  if (value == linkdata->best) {
+    return LQ_QUALITY_BEST;
+  }
+  if (value == linkdata->worst) {
+    return LQ_QUALITY_WORST;
+  }
+
+  if (linkdata->best < linkdata->worst) {
+    if (value > linkdata->good) {
+      return LQ_QUALITY_GOOD;
     }
-  } else {
-    if (cost >= LINK_COST_BROKEN) {
-      return infinite;
+    if (value > linkdata->average) {
+      return LQ_QUALITY_AVERAGE;
+    }
+  }
+  else {
+    if (value < linkdata->good) {
+      return LQ_QUALITY_GOOD;
+    }
+    if (value < linkdata->average) {
+      return LQ_QUALITY_AVERAGE;
     }
   }
-  return active_lq_handler->print_cost(cost, buffer);
+  return LQ_QUALITY_BAD;
 }
 
 /*
index cdfbac9..0698615 100644 (file)
 #include "lq_packet.h"
 #include "common/avl.h"
 
-#define LINK_COST_BROKEN (1<<22)
+#define LINK_COST_BROKEN (0x00ffffff)
 #define ROUTE_COST_BROKEN (0xffffffff)
 #define ZERO_ROUTE_COST 0
 
 #define MINIMAL_USEFUL_LQ 0.1
 #define LQ_PLUGIN_RELEVANT_COSTCHANGE 16
 
-struct lqtextbuffer {
-  char buf[16];
+#define LQTEXT_MAXLENGTH 32
+
+struct lq_linkdata_type {
+  const char *name;
+  size_t name_maxlen;
+  int32_t best, good, average, worst;
+};
+
+enum lq_linkdata_quality {
+  LQ_QUALITY_BEST,
+  LQ_QUALITY_GOOD,
+  LQ_QUALITY_AVERAGE,
+  LQ_QUALITY_BAD,
+  LQ_QUALITY_WORST
 };
 
 struct lq_handler {
@@ -65,16 +77,17 @@ struct lq_handler {
   void (*initialize) (void);
   void (*deinitialize) (void);
 
-    olsr_linkcost(*calc_link_entry_cost) (struct link_entry *);
-    olsr_linkcost(*calc_lq_hello_neighbor_cost) (struct lq_hello_neighbor *);
-    olsr_linkcost(*calc_tc_mpr_addr_cost) (struct tc_mpr_addr *);
-    olsr_linkcost(*calc_tc_edge_entry_cost) (struct tc_edge_entry *);
+  olsr_linkcost(*calc_link_entry_cost) (struct link_entry *);
+  olsr_linkcost(*calc_lq_hello_neighbor_cost) (struct lq_hello_neighbor *);
+  olsr_linkcost(*calc_tc_mpr_addr_cost) (struct tc_mpr_addr *);
+  olsr_linkcost(*calc_tc_edge_entry_cost) (struct tc_edge_entry *);
 
-    bool(*is_relevant_costchange) (olsr_linkcost c1, olsr_linkcost c2);
+  bool(*is_relevant_costchange) (olsr_linkcost c1, olsr_linkcost c2);
 
-    olsr_linkcost(*packet_loss_handler) (struct link_entry *, bool);
+  olsr_linkcost(*packet_loss_handler) (struct link_entry *, bool);
 
   void (*memorize_foreign_hello) (struct link_entry *, struct lq_hello_neighbor *);
+
   void (*copy_link_entry_lq_into_tc_mpr_addr) (struct tc_mpr_addr *, struct link_entry *);
   void (*copy_link_entry_lq_into_tc_edge_entry) (struct tc_edge_entry *, struct link_entry *);
   void (*copy_link_lq_into_neighbor) (struct lq_hello_neighbor *, struct link_entry *);
@@ -89,9 +102,13 @@ struct lq_handler {
   void (*deserialize_hello_lq) (uint8_t const **, struct lq_hello_neighbor *);
   void (*deserialize_tc_lq) (uint8_t const **, struct tc_edge_entry *);
 
-  char *(*print_link_entry_lq) (struct link_entry *, char, struct lqtextbuffer *);
-  char *(*print_tc_edge_entry_lq) (struct tc_edge_entry *, char, struct lqtextbuffer *);
-  char *(*print_cost) (olsr_linkcost cost, struct lqtextbuffer *);
+  int (*get_link_entry_data) (struct link_entry *, int);
+
+  const char *(*print_cost) (olsr_linkcost cost, char *, size_t);
+  const char *(*print_link_entry_lq) (struct link_entry *, int, char *, size_t);
+
+  struct lq_linkdata_type *linkdata_hello;
+  int linkdata_hello_count;
 
   size_t size_tc_edge;
   size_t size_tc_mpr_addr;
@@ -119,16 +136,16 @@ void olsr_deserialize_tc_lq_pair(const uint8_t **, struct tc_edge_entry *);
 void olsr_update_packet_loss_worker(struct link_entry *, bool);
 void olsr_memorize_foreign_hello_lq(struct link_entry *, struct lq_hello_neighbor *);
 
-const char *EXPORT(get_link_entry_text) (struct link_entry *, char, struct lqtextbuffer *);
-const char *EXPORT(get_tc_edge_entry_text) (struct tc_edge_entry *, char, struct lqtextbuffer *);
-const char *EXPORT(get_linkcost_text) (olsr_linkcost, bool, struct lqtextbuffer *);
+const char *EXPORT(olsr_get_linkcost_text) (olsr_linkcost, bool, char *, size_t);
+const char *EXPORT(olsr_get_linkdata_text) (struct link_entry *, int, char *, size_t);
+const char *EXPORT(olsr_get_linklabel) (int);
+size_t EXPORT(olsr_get_linklabel_maxlength) (int);
+size_t EXPORT(olsr_get_linklabel_count) (void);
+enum lq_linkdata_quality EXPORT(olsr_get_linkdata_quality) (struct link_entry *, int);
 
 void olsr_copy_hello_lq(struct lq_hello_neighbor *, struct link_entry *);
 void olsr_copylq_link_entry_2_tc_mpr_addr(struct tc_mpr_addr *, struct link_entry *);
 void olsr_copylq_link_entry_2_tc_edge_entry(struct tc_edge_entry *, struct link_entry *);
-#if 0
-void olsr_clear_tc_lq(struct tc_mpr_addr *);
-#endif
 
 struct tc_edge_entry *olsr_malloc_tc_edge_entry(void);
 struct tc_mpr_addr *olsr_malloc_tc_mpr_addr(void);
@@ -149,7 +166,6 @@ size_t olsr_sizeof_TCLQ(void);
 /* Externals. */
 extern struct lq_handler *EXPORT(active_lq_handler);
 
-
 #endif /*LQPLUGIN_H_ */
 
 /*
index a850287..c530156 100644 (file)
@@ -459,7 +459,7 @@ olsr_print_neighbor_table(void)
   struct ipaddr_str buf;
   struct nbr2_entry *nbr2;
   struct nbr_con *connector;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
   bool first;
 
   OLSR_INFO(LOG_NEIGHTABLE, "\n--- %s ------------------------------------------------ NEIGHBORS\n\n"
@@ -489,7 +489,7 @@ olsr_print_neighbor_table(void)
       OLSR_INFO_NH(LOG_2NEIGH, "%-*s  %-*s  %s\n",
                    ipwidth, first ? olsr_ip_to_string(&buf, &nbr2->nbr2_addr) : "",
                    ipwidth, olsr_ip_to_string(&buf, &connector->nbr->nbr_addr),
-                   get_linkcost_text(connector->path_linkcost, false, &lqbuffer));
+                   olsr_get_linkcost_text(connector->path_linkcost, false, lqbuffer, sizeof(lqbuffer)));
 
       first = false;
     } OLSR_FOR_ALL_NBR2_CON_ENTRIES_END(nbr2, connector);
index d07e4f8..5aceb66 100644 (file)
@@ -228,7 +228,6 @@ static void olsr_com_parse_request(int fd, void *data __attribute__ ((unused)),
   abuf_init(&con->out, 0);
 
   con->is_http = fd == comsocket_http;
-  con->is_csv = false;
   con->fd = sock;
 
   if (olsr_cnf->ip_version == AF_INET6) {
@@ -626,8 +625,8 @@ static void olsr_com_parse_txt(struct comport_connection *con,
             con->state = SEND_AND_QUIT;
             break;
         }
-        /* put an empty line behind each command if not in csv mode */
-        if (!con->is_csv) {
+        /* put an empty line behind each command */
+        if (con->show_echo) {
           abuf_puts(&con->out, "\n");
         }
       }
@@ -648,7 +647,7 @@ static void olsr_com_parse_txt(struct comport_connection *con,
   }
 
   /* print prompt */
-  if (processedCommand && con->state == INTERACTIVE && !con->is_csv) {
+  if (processedCommand && con->state == INTERACTIVE && con->show_echo) {
     abuf_puts(&con->out, "> ");
   }
 }
index 39c288b..8bb0392 100644 (file)
@@ -79,9 +79,6 @@ struct comport_connection {
   /* ip addr of peer (R) */
   union olsr_ip_addr addr;
 
-  /* true if the txt session is in CSV mode (RW) */
-  bool is_csv;
-
   /* callback and data to stop a continous output txt command (RW) */
   olsr_txt_stop_continous stop_handler;
   void *stop_data[4];
@@ -98,7 +95,7 @@ struct comport_connection {
   enum connection_state state;
   enum http_header_type send_as;
   struct timer_entry *timeout;
-  bool is_http;
+  bool is_http, show_echo;
   struct autobuf in;
 };
 
index 4ac53eb..0ac534b 100644 (file)
@@ -58,16 +58,14 @@ struct txt_repeat_data {
   bool csv;
 };
 
-static struct avl_tree txt_normal_tree, txt_csv_tree, txt_help_tree;
+static struct avl_tree txt_normal_tree, txt_help_tree;
 static struct olsr_cookie_info *txtcommand_cookie, *txt_repeattimer_cookie;
 
 static enum olsr_txtcommand_result olsr_txtcmd_quit(
     struct comport_connection *con, char *cmd, char *param);
 static enum olsr_txtcommand_result olsr_txtcmd_help(
     struct comport_connection *con, char *cmd, char *param);
-static enum olsr_txtcommand_result olsr_txtcmd_csv(
-    struct comport_connection *con, char *cmd, char *param);
-static enum olsr_txtcommand_result olsr_txtcmd_csvoff(
+static enum olsr_txtcommand_result olsr_txtcmd_echo(
     struct comport_connection *con, char *cmd, char *param);
 static enum olsr_txtcommand_result olsr_txtcmd_repeat(
     struct comport_connection *con, char *cmd, char *param);
@@ -85,8 +83,7 @@ static const char *txt_internal_names[] = {
   "quit",
   "exit",
   "help",
-  "csv",
-  "csvoff",
+  "echo",
   "repeat",
   "timeout",
   "version",
@@ -97,8 +94,7 @@ static const char *txt_internal_help[] = {
   "shuts down the terminal connection\n",
   "shuts down the terminal connection\n",
   "display the online help text\n",
-  "activates the csv (comma separated value) flag\n",
-  "deactivates the csv (comma separated value) flag\n",
+  "switchs the prompt on/off\n",
   "repeat <interval> <command>: repeats a command every <interval> seconds\n",
   "timeout <interval>: set the timeout interval to <interval> seconds, 0 means no timeout\n"
   "displays the version of the olsrd\n"
@@ -110,8 +106,7 @@ static olsr_txthandler txt_internal_handlers[] = {
   olsr_txtcmd_quit,
   olsr_txtcmd_quit,
   olsr_txtcmd_help,
-  olsr_txtcmd_csv,
-  olsr_txtcmd_csvoff,
+  olsr_txtcmd_echo,
   olsr_txtcmd_repeat,
   olsr_txtcmd_timeout,
   olsr_txtcmd_version,
@@ -123,7 +118,6 @@ olsr_com_init_txt(void) {
   size_t i;
 
   avl_init(&txt_normal_tree, &avl_comp_strcasecmp);
-  avl_init(&txt_csv_tree, &avl_comp_strcasecmp);
   avl_init(&txt_help_tree, &avl_comp_strcasecmp);
 
   txtcommand_cookie = olsr_alloc_cookie("comport txt commands", OLSR_COOKIE_TYPE_MEMORY);
@@ -133,7 +127,6 @@ olsr_com_init_txt(void) {
 
   for (i=0; i < ARRAYSIZE(txt_internal_names); i++) {
     olsr_com_add_normal_txtcommand(txt_internal_names[i], txt_internal_handlers[i]);
-    olsr_com_add_csv_txtcommand(txt_internal_names[i], txt_internal_handlers[i]);
     olsr_com_add_help_txtcommand(txt_internal_names[i], olsr_txtcmd_displayhelp);
   }
 }
@@ -147,10 +140,6 @@ olsr_com_destroy_txt(void) {
     cmd = txt_tree2cmd(node);
     olsr_com_remove_normal_txtcommand(cmd);
   }
-  while ((node = avl_walk_first(&txt_csv_tree)) != NULL) {
-    cmd = txt_tree2cmd(node);
-    olsr_com_remove_csv_txtcommand(cmd);
-  }
   while ((node = avl_walk_first(&txt_help_tree)) != NULL) {
     cmd = txt_tree2cmd(node);
     olsr_com_remove_help_txtcommand(cmd);
@@ -168,18 +157,6 @@ olsr_com_add_normal_txtcommand (const char *command, olsr_txthandler handler) {
   return txt;
 }
 
-struct olsr_txtcommand *
-olsr_com_add_csv_txtcommand (const char *command, olsr_txthandler handler) {
-  struct olsr_txtcommand *txt;
-
-  txt = olsr_cookie_malloc(txtcommand_cookie);
-  txt->node.key = strdup(command);
-  txt->handler = handler;
-
-  avl_insert(&txt_csv_tree, &txt->node, AVL_DUP_NO);
-  return txt;
-}
-
 struct olsr_txtcommand *
 olsr_com_add_help_txtcommand (const char *command, olsr_txthandler handler) {
   struct olsr_txtcommand *txt;
@@ -198,12 +175,6 @@ void olsr_com_remove_normal_txtcommand (struct olsr_txtcommand *cmd) {
   olsr_cookie_free(txtcommand_cookie, cmd);
 }
 
-void olsr_com_remove_csv_txtcommand (struct olsr_txtcommand *cmd) {
-  avl_delete(&txt_csv_tree, &cmd->node);
-  free(cmd->node.key);
-  olsr_cookie_free(txtcommand_cookie, cmd);
-}
-
 void olsr_com_remove_help_txtcommand (struct olsr_txtcommand *cmd) {
   avl_delete(&txt_help_tree, &cmd->node);
   free(cmd->node.key);
@@ -214,10 +185,10 @@ enum olsr_txtcommand_result
 olsr_com_handle_txtcommand(struct comport_connection *con, char *cmd, char *param) {
   struct olsr_txtcommand *ptr;
 
-  ptr = (struct olsr_txtcommand *) avl_find(con->is_csv ? (&txt_csv_tree) : (&txt_normal_tree), cmd);
+  ptr = (struct olsr_txtcommand *) avl_find(&txt_normal_tree, cmd);
 
-  OLSR_DEBUG(LOG_COMPORT, "Looking for command '%s' (%s): %s\n",
-    cmd, con->is_csv ? "csv" : "normal", ptr ? "unknown" : "available");
+  OLSR_DEBUG(LOG_COMPORT, "Looking for command '%s': %s\n",
+    cmd, ptr ? "unknown" : "available");
   if (ptr == NULL) {
     return UNKNOWN;
   }
@@ -264,31 +235,38 @@ olsr_txtcmd_help(struct comport_connection *con,
     return UNKNOWN;
   }
 
-  if (!con->is_csv) {
-    abuf_puts(&con->out, "Known commands:\n");
+  if (abuf_puts(&con->out, "Known commands:\n") < 0) {
+    return ABUF_ERROR;
   }
 
-  ptr = (struct olsr_txtcommand *)avl_walk_first(con->is_csv ? (&txt_csv_tree) : (&txt_normal_tree));
+  ptr = (struct olsr_txtcommand *)avl_walk_first(&txt_normal_tree);
   while (ptr) {
-    abuf_appendf(&con->out, con->is_csv ? ",%s" : "  %s\n", (char *)ptr->node.key);
+    if (abuf_appendf(&con->out, "  %s\n", (char *)ptr->node.key) < 0) {
+      return ABUF_ERROR;
+    }
     ptr = (struct olsr_txtcommand *)avl_walk_next(&ptr->node);
   }
 
-  abuf_puts(&con->out, con->is_csv ? "\n" : "Use 'help <command> to see a help text for a certain command\n");
-  return CONTINUE;
-}
-
-static enum olsr_txtcommand_result
-olsr_txtcmd_csv(struct comport_connection *con,
-    char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
-  con->is_csv = true;
+  if (abuf_puts(&con->out, "Use 'help <command> to see a help text for a certain command\n") < 0) {
+    return ABUF_ERROR;
+  }
   return CONTINUE;
 }
 
 static enum olsr_txtcommand_result
-olsr_txtcmd_csvoff(struct comport_connection *con,
-    char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
-  con->is_csv = false;
+olsr_txtcmd_echo(struct comport_connection *con,
+    char *cmd __attribute__ ((unused)), char *param) {
+  if (strcasecmp(param, "on") == 0) {
+    con->show_echo = true;
+  }
+  else if (strcasecmp(param, "off") == 0) {
+    con->show_echo = false;
+  }
+  else {
+    if (abuf_appendf(&con->out, "Error, unknown argument '%s' for echo. Try 'on' or 'off'\n", param) < 0) {
+      return ABUF_ERROR;
+    }
+  }
   return CONTINUE;
 }
 
@@ -361,8 +339,7 @@ olsr_txtcmd_repeat(struct comport_connection *con, char *cmd __attribute__ ((unu
 
 static enum olsr_txtcommand_result
 olsr_txtcmd_version(struct comport_connection *con, char *cmd __attribute__ ((unused)), char *param __attribute__ ((unused))) {
-  abuf_appendf(&con->out,
-      con->is_csv ? "version,%s,%s,%s\n" : " *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n",
+  abuf_appendf(&con->out, " *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n",
       olsrd_version, build_date, build_host);
   return CONTINUE;
 }
@@ -372,11 +349,11 @@ olsr_txtcmd_plugin(struct comport_connection *con, char *cmd, char *param) {
   struct olsr_plugin *plugin;
   char *para2 = NULL;
   if (param == NULL || strcasecmp(param, "list") == 0) {
-    if (!con->is_csv && abuf_puts(&con->out, "Table:\n") < 0) {
+    if (abuf_puts(&con->out, "Table:\n") < 0) {
       return ABUF_ERROR;
     }
     OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) {
-      if (abuf_appendf(&con->out, con->is_csv ? "%s,%s,%s": " %-30s\t%s\t%s\n",
+      if (abuf_appendf(&con->out, " %-30s\t%s\t%s\n",
           plugin->p_name, plugin->active ? "active" : "", plugin->dlhandle == NULL ? "static" : "") < 0) {
         return ABUF_ERROR;
       }
@@ -386,8 +363,8 @@ olsr_txtcmd_plugin(struct comport_connection *con, char *cmd, char *param) {
 
   para2 = strchr(param, ' ');
   if (para2 == NULL) {
-    if (con->is_csv) {
-      abuf_appendf(&con->out, "Error, missing or unknown parameter\n");
+    if (abuf_appendf(&con->out, "Error, missing or unknown parameter\n") < 0) {
+      return ABUF_ERROR;
     }
     return CONTINUE;
   }
@@ -410,8 +387,8 @@ olsr_txtcmd_plugin(struct comport_connection *con, char *cmd, char *param) {
   }
 
   if (plugin == NULL) {
-    if (con->is_csv) {
-      abuf_appendf(&con->out, "Error, could not find plugin '%s'.\n", para2);
+    if (abuf_appendf(&con->out, "Error, could not find plugin '%s'.\n", para2) < 0) {
+      return ABUF_ERROR;
     }
     return CONTINUE;
   }
index 53ef06f..b2f324d 100644 (file)
@@ -72,8 +72,6 @@ void olsr_com_destroy_txt(void);
 
 struct olsr_txtcommand *EXPORT(olsr_com_add_normal_txtcommand) (
     const char *command, olsr_txthandler handler);
-struct olsr_txtcommand *EXPORT(olsr_com_add_csv_txtcommand) (
-    const char *command, olsr_txthandler handler);
 struct olsr_txtcommand *EXPORT(olsr_com_add_help_txtcommand) (
     const char *command, olsr_txthandler handler);
 void EXPORT(olsr_com_remove_normal_txtcommand) (struct olsr_txtcommand *cmd);
index 66a0592..ca52aee 100644 (file)
@@ -82,12 +82,12 @@ olsr_spf_add_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
 {
 #if !defined REMOVE_LOG_DEBUG
   struct ipaddr_str buf;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
   tc->cand_tree_node.key = &tc->path_cost;
 
   OLSR_DEBUG(LOG_ROUTING, "SPF: insert candidate %s, cost %s\n",
-             olsr_ip_to_string(&buf, &tc->addr), get_linkcost_text(tc->path_cost, false, &lqbuffer));
+             olsr_ip_to_string(&buf, &tc->addr), olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)));
 
   avl_insert(tree, &tc->cand_tree_node, AVL_DUP);
 }
@@ -103,10 +103,10 @@ olsr_spf_del_cand_tree(struct avl_tree *tree, struct tc_entry *tc)
 
 #if !defined REMOVE_LOG_DEBUG
   struct ipaddr_str buf;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
   OLSR_DEBUG(LOG_ROUTING, "SPF: delete candidate %s, cost %s\n",
-             olsr_ip_to_string(&buf, &tc->addr), get_linkcost_text(tc->path_cost, false, &lqbuffer));
+             olsr_ip_to_string(&buf, &tc->addr), olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)));
 
   avl_delete(tree, &tc->cand_tree_node);
 }
@@ -121,12 +121,12 @@ olsr_spf_add_path_list(struct list_node *head, int *path_count, struct tc_entry
 {
 #if !defined REMOVE_LOG_DEBUG
   struct ipaddr_str pathbuf, nbuf;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
 
   OLSR_DEBUG(LOG_ROUTING, "SPF: append path %s, cost %s, via %s\n",
              olsr_ip_to_string(&pathbuf, &tc->addr),
-             get_linkcost_text(tc->path_cost, false, &lqbuffer),
+             olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)),
              tc->next_hop ? olsr_ip_to_string(&nbuf, &tc->next_hop->neighbor_iface_addr) : "-");
 
   list_add_before(head, &tc->path_list_node);
@@ -162,10 +162,11 @@ olsr_spf_relax(struct avl_tree *cand_tree, struct tc_entry *tc)
 
 #if !defined REMOVE_LOG_DEBUG
   struct ipaddr_str buf, nbuf;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 #endif
   OLSR_DEBUG(LOG_ROUTING, "SPF: exploring node %s, cost %s\n",
-             olsr_ip_to_string(&buf, &tc->addr), get_linkcost_text(tc->path_cost, false, &lqbuffer));
+             olsr_ip_to_string(&buf, &tc->addr),
+             olsr_get_linkcost_text(tc->path_cost, false, lqbuffer, sizeof(lqbuffer)));
 
   /*
    * loop through all edges of this vertex.
@@ -193,7 +194,8 @@ olsr_spf_relax(struct avl_tree *cand_tree, struct tc_entry *tc)
     new_cost = tc->path_cost + tc_edge->common_cost;
 
     OLSR_DEBUG(LOG_ROUTING, "SPF:   exploring edge %s, cost %s\n",
-               olsr_ip_to_string(&buf, &tc_edge->T_dest_addr), get_linkcost_text(new_cost, true, &lqbuffer));
+               olsr_ip_to_string(&buf, &tc_edge->T_dest_addr),
+               olsr_get_linkcost_text(new_cost, true, lqbuffer, sizeof(lqbuffer)));
 
     /*
      * if it's better than the current path quality of this edge's
@@ -220,7 +222,7 @@ olsr_spf_relax(struct avl_tree *cand_tree, struct tc_entry *tc)
 
       OLSR_DEBUG(LOG_ROUTING, "SPF:   better path to %s, cost %s, via %s, hops %d\n",
                  olsr_ip_to_string(&buf, &new_tc->addr),
-                 get_linkcost_text(new_cost, true, &lqbuffer),
+                 olsr_get_linkcost_text(new_cost, true, lqbuffer, sizeof(lqbuffer)),
                  tc->next_hop ? olsr_ip_to_string(&nbuf, &tc->next_hop->neighbor_iface_addr) : "<none>", new_tc->hops);
     }
   }
index 1daa9e6..6bcf18a 100644 (file)
@@ -724,7 +724,7 @@ olsr_rtp_to_string(const struct rt_path *rtp)
 {
   static char buff[128];
   struct ipaddr_str origstr, gwstr;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
   struct ipprefix_str prefixstr;
 
   snprintf(buff, sizeof(buff),
@@ -734,7 +734,8 @@ olsr_rtp_to_string(const struct rt_path *rtp)
            olsr_ip_to_string(&origstr, &rtp->rtp_originator.prefix),
            olsr_ip_to_string(&gwstr, &rtp->rtp_nexthop.gateway),
            rtp->rtp_nexthop.interface ? rtp->rtp_nexthop.interface->int_name : "(null)",
-           get_linkcost_text(rtp->rtp_metric.cost, true, &lqbuffer), rtp->rtp_metric.hops, rtp->rtp_version);
+           olsr_get_linkcost_text(rtp->rtp_metric.cost, true, lqbuffer, sizeof(lqbuffer)),
+           rtp->rtp_metric.hops, rtp->rtp_version);
 
   return buff;
 }
@@ -749,7 +750,7 @@ olsr_print_routing_table(struct avl_tree *tree __attribute__ ((unused)))
   /* The whole function makes no sense without it. */
 #if !defined REMOVE_LOG_INFO
   struct avl_node *rt_tree_node;
-  struct lqtextbuffer lqbuffer;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 
   OLSR_INFO(LOG_ROUTING, "ROUTING TABLE\n");
 
@@ -771,7 +772,7 @@ olsr_print_routing_table(struct avl_tree *tree __attribute__ ((unused)))
       struct rt_path *rtp = rtp_tree2rtp(rtp_tree_node);
       OLSR_INFO_NH(LOG_ROUTING, "\tfrom %s, cost %s, metric %u, via %s, dev %s, v %u\n",
                    olsr_ip_to_string(&origstr, &rtp->rtp_originator.prefix),
-                   get_linkcost_text(rtp->rtp_metric.cost, true, &lqbuffer),
+                   olsr_get_linkcost_text(rtp->rtp_metric.cost, true, lqbuffer, sizeof(lqbuffer)),
                    rtp->rtp_metric.hops,
                    olsr_ip_to_string(&gwstr, &rtp->rtp_nexthop.gateway),
                    rt->rt_nexthop.interface ? rt->rt_nexthop.interface->int_name : "(null)", rtp->rtp_version);
index 513cbd6..e45a993 100644 (file)
@@ -298,13 +298,13 @@ olsr_tc_edge_to_string(struct tc_edge_entry *tc_edge)
 {
   static char buf[128];
   struct ipaddr_str addrbuf, dstbuf;
-  struct lqtextbuffer lqbuffer1, lqbuffer2;
+  char lqbuffer[LQTEXT_MAXLENGTH];
 
   snprintf(buf, sizeof(buf),
-           "%s > %s, cost (%6s) %s",
+           "%s > %s, cost %s",
            olsr_ip_to_string(&addrbuf, &tc_edge->tc->addr),
            olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr),
-           get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
+           olsr_get_linkcost_text(tc_edge->cost, false, lqbuffer, sizeof(lqbuffer)));
   return buf;
 }
 #endif
@@ -690,14 +690,14 @@ olsr_print_tc_table(void)
   const int ipwidth = olsr_cnf->ip_version == AF_INET ? 15 : 30;
 
   OLSR_INFO(LOG_TC, "\n--- %s ------------------------------------------------- TOPOLOGY\n\n", olsr_wallclock_string());
-  OLSR_INFO_NH(LOG_TC, "%-*s %-*s             %-14s  %8s %8s\n", ipwidth,
-               "Source IP addr", ipwidth, "Dest IP addr", "      LQ      ", "ETX", "(common)");
+  OLSR_INFO_NH(LOG_TC, "%-*s %-*s             %8s %8s\n", ipwidth,
+               "Source IP addr", ipwidth, "Dest IP addr", olsr_get_linklabel(0), "(common)");
 
   OLSR_FOR_ALL_TC_ENTRIES(tc) {
     struct tc_edge_entry *tc_edge;
     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
       struct ipaddr_str addrbuf, dstaddrbuf;
-      struct lqtextbuffer lqbuffer1, lqbuffer2, lqbuffer3;
+      char lqbuffer1[LQTEXT_MAXLENGTH], lqbuffer2[LQTEXT_MAXLENGTH];
       char *type = NORMAL;
       /* there should be no local virtual edges ! */
       if (tc_edge->is_local) {
@@ -707,14 +707,13 @@ olsr_print_tc_table(void)
         type = VIRTUAL;
       }
 
-      OLSR_INFO_NH(LOG_TC, "%-*s %-*s %-7s      %-14s %8s/%8s\n",
+      OLSR_INFO_NH(LOG_TC, "%-*s %-*s %-7s      %8s %8s\n",
                    ipwidth, olsr_ip_to_string(&addrbuf, &tc->addr),
                    ipwidth, olsr_ip_to_string(&dstaddrbuf,
                                               &tc_edge->T_dest_addr),
                    type,
-                   get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1),
-                   get_linkcost_text(tc_edge->cost, false, &lqbuffer2),
-                   get_linkcost_text(tc_edge->common_cost, false, &lqbuffer3));
+                   olsr_get_linkcost_text(tc_edge->cost, false, lqbuffer1, sizeof(lqbuffer1)),
+                   olsr_get_linkcost_text(tc_edge->common_cost, false, lqbuffer2, sizeof(lqbuffer2)));
 
     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);