add interfaces command to txtinfo
[olsrd.git] / lib / txtinfo / src / olsrd_txtinfo.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45 #include "olsr.h"
46 #include "ipcalc.h"
47 #include "neighbor_table.h"
48 #include "tc_set.h"
49 #include "hna_set.h"
50 #include "mid_set.h"
51 #include "routing_table.h"
52 #include "olsr_ip_prefix_list.h"
53 #include "parser.h"
54 #include "olsr_comport_txt.h"
55 #include "olsr_comport_http.h"
56 #include "common/string.h"
57 #include "common/autobuf.h"
58 #include "plugin_loader.h"
59 #include "plugin_util.h"
60
61 #define PLUGIN_DESCR    "OLSRD txtinfo plugin"
62 #define PLUGIN_AUTHOR   "Henning Rogge"
63
64
65 struct txtinfo_cmd {
66   const char *name;
67   olsr_txthandler handler;
68   struct olsr_txtcommand *cmd;
69 };
70
71 static bool txtinfo_init(void);
72 static bool txtinfo_enable(void);
73 static bool txtinfo_disable(void);
74 static bool txtinfo_exit(void);
75
76 static enum olsr_txtcommand_result txtinfo_neigh(struct comport_connection *con,
77     const char *cmd, const char *param);
78 static enum olsr_txtcommand_result txtinfo_link(struct comport_connection *con,
79     const char *cmd, const char *param);
80 static enum olsr_txtcommand_result txtinfo_routes(struct comport_connection *con,
81     const char *cmd, const char *param);
82 static enum olsr_txtcommand_result txtinfo_topology(struct comport_connection *con,
83     const char *cmd, const char *param);
84 static enum olsr_txtcommand_result txtinfo_hna(struct comport_connection *con,
85     const char *cmd, const char *param);
86 static enum olsr_txtcommand_result txtinfo_mid(struct comport_connection *con,
87     const char *cmd, const char *param);
88 static enum olsr_txtcommand_result txtinfo_interfaces(struct comport_connection *con,
89     const char *cmd, const char *param);
90
91 /* plugin configuration */
92 static struct ip_acl allowed_nets;
93
94 /* plugin parameters */
95 static const struct olsrd_plugin_parameters plugin_parameters[] = {
96   {.name = IP_ACL_ACCEPT_PARAP,.set_plugin_parameter = &ip_acl_add_plugin_accept,.data = &allowed_nets},
97   {.name = IP_ACL_REJECT_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_reject,.data = &allowed_nets},
98   {.name = IP_ACL_CHECKFIRST_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_checkFirst,.data = &allowed_nets},
99   {.name = IP_ACL_DEFAULTPOLICY_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_defaultPolicy,.data = &allowed_nets}
100 };
101
102 OLSR_PLUGIN6(plugin_parameters) {
103   .descr = PLUGIN_DESCR,
104   .author = PLUGIN_AUTHOR,
105   .init = txtinfo_init,
106   .enable = txtinfo_enable,
107   .disable = txtinfo_disable,
108   .exit = txtinfo_exit,
109   .deactivate = true
110 };
111
112 /* command callbacks and names */
113 static struct txtinfo_cmd commands[] = {
114     {"link", &txtinfo_link, NULL},
115     {"neigh", &txtinfo_neigh, NULL},
116     {"topology", &txtinfo_topology, NULL},
117     {"hna", &txtinfo_hna, NULL},
118     {"mid", &txtinfo_mid, NULL},
119     {"routes", &txtinfo_routes, NULL},
120     {"interfaces", &txtinfo_interfaces, NULL},
121 };
122
123 /* base path for http access (should end with a '/') */
124 static const char TXTINFO_HTTP_PATH[] = "/txtinfo/";
125
126 /* constants and static storage for template engine */
127 static const char KEY_LOCALIP[] = "localip";
128 static const char KEY_NEIGHIP[] = "neighip";
129 static const char KEY_ALIASIP[] = "aliasip";
130 static const char KEY_DESTPREFIX[] = "destprefix";
131 static const char KEY_SYM[] = "issym";
132 static const char KEY_MPR[] = "ismpr";
133 static const char KEY_MPRS[] = "ismprs";
134 static const char KEY_VIRTUAL[] = "isvirtual";
135 static const char KEY_WILLINGNESS[] = "will";
136 static const char KEY_2HOP[] = "2hop";
137 static const char KEY_LINKCOST[] = "linkcost";
138 static const char KEY_RAWLINKCOST[] = "rawlinkcost";
139 static const char KEY_HOPCOUNT[] = "hopcount";
140 static const char KEY_INTERFACE[] = "interface";
141 static const char KEY_VTIME[] = "vtime";
142 static const char KEY_STATE[] = "state";
143 static const char KEY_MTU[] = "mtu";
144 static const char KEY_SRCIP[] = "srcip";
145 static const char KEY_DSTIP[] = "dstip";
146
147 static struct ipaddr_str buf_localip, buf_neighip, buf_aliasip, buf_srcip, buf_dstip;
148 struct ipprefix_str buf_destprefix;
149 static char buf_sym[6], buf_mrp[4], buf_mprs[4], buf_virtual[4];
150 static char buf_willingness[7];
151 static char buf_2hop[6];
152 static char buf_rawlinkcost[11];
153 static char buf_linkcost[LQTEXT_MAXLENGTH];
154 static char buf_hopcount[4];
155 static char buf_state[5];
156 static char buf_mtu[5];
157 static char buf_interface[IF_NAMESIZE];
158 struct millitxt_buf buf_vtime;
159
160 static size_t tmpl_indices[32];
161
162 /* a link metric may contain up to 8 values */
163 static const char *keys_link[] = {
164   KEY_LOCALIP, KEY_NEIGHIP, KEY_SYM, KEY_MPR, KEY_VTIME,
165   KEY_RAWLINKCOST, KEY_LINKCOST,
166   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
167 };
168 static char *values_link[] = {
169   buf_localip.buf, buf_neighip.buf, buf_sym, buf_mrp, buf_vtime.buf,
170   buf_rawlinkcost, buf_linkcost,
171   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
172 };
173 static char tmpl_link[256], headline_link[256];
174 static size_t link_keys_static = 0, link_keys_count = 0, link_value_size = 0;
175
176 static const char *tmpl_neigh = "%neighip%\t%issym%\t%ismpr%\t%ismprs%\t%will%\t%2hop%\n";
177 static const char *keys_neigh[] = {
178   KEY_NEIGHIP, KEY_SYM, KEY_MPR, KEY_MPRS, KEY_WILLINGNESS, KEY_2HOP
179 };
180 static char *values_neigh[] = {
181   buf_neighip.buf, buf_sym, buf_mprs, buf_mprs, buf_willingness, buf_2hop
182 };
183
184 static const char *tmpl_routes = "%destprefix%\t%neighip%\t%hopcount%\t%linkcost%\t%interface%\n";
185 static const char *keys_routes[] = {
186   KEY_DESTPREFIX, KEY_NEIGHIP, KEY_HOPCOUNT, KEY_VTIME,
187   KEY_INTERFACE, KEY_RAWLINKCOST, KEY_LINKCOST
188 };
189 static char *values_routes[] = {
190   buf_destprefix.buf, buf_neighip.buf, buf_hopcount, buf_vtime.buf,
191   buf_interface, buf_rawlinkcost, buf_linkcost
192 };
193
194 static const char *tmpl_topology = "%neighip%\t%localip%\t%isvirtual%\t%linkcost%\n";
195 static const char *keys_topology[] = {
196   KEY_LOCALIP, KEY_NEIGHIP, KEY_VIRTUAL, KEY_VTIME,
197   KEY_RAWLINKCOST, KEY_LINKCOST
198 };
199 static char *values_topology[] = {
200   buf_localip.buf, buf_neighip.buf, buf_virtual, buf_vtime.buf,
201   buf_rawlinkcost, buf_linkcost
202 };
203
204 static const char *tmpl_hna = "%destprefix%\t%localip%\t%vtime%\n";
205 static const char *keys_hna[] = {
206   KEY_LOCALIP, KEY_DESTPREFIX, KEY_VTIME
207 };
208 static char *values_hna[] = {
209   buf_localip.buf, buf_destprefix.buf, buf_vtime.buf
210 };
211
212 static const char *tmpl_mid = "%localip%\t%aliasip%\t%vtime%\n";
213 static const char *keys_mid[] = {
214   KEY_LOCALIP, KEY_ALIASIP, KEY_VTIME
215 };
216 static char *values_mid[] = {
217   buf_localip.buf, buf_aliasip.buf, buf_vtime.buf
218 };
219
220 static const char *tmpl_interface = "%interface%\t%state%\t%mtu%\t%srcip%\t%dstip%\n";
221 static const char *keys_interface[] = {
222   KEY_INTERFACE, KEY_STATE, KEY_MTU, 
223   KEY_SRCIP, KEY_DSTIP
224 };
225 static char *values_interface[] = {
226   buf_interface, buf_state, buf_mtu, 
227   buf_srcip.buf, buf_dstip.buf
228 };
229
230 /**
231  * Constructor of plugin, called before parameters are initialized
232  */
233 static bool
234 txtinfo_init(void)
235 {
236   ip_acl_init(&allowed_nets);
237
238   /* always allow localhost */
239   if (olsr_cnf->ip_version == AF_INET) {
240     union olsr_ip_addr ip;
241
242     ip.v4.s_addr = ntohl(INADDR_LOOPBACK);
243     ip_acl_add(&allowed_nets, &ip, 32, false);
244   } else {
245     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_loopback, 128, false);
246     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_v4mapped_loopback, 128, false);
247   }
248   return false;
249 }
250
251 /**
252  * Destructor of plugin
253  */
254 static bool
255 txtinfo_disable(void)
256 {
257   size_t i;
258
259   for (i=0; i<ARRAYSIZE(commands); i++) {
260     olsr_com_remove_normal_txtcommand(commands[i].cmd);
261   }
262   for (i=link_keys_static; i<link_keys_count; i++) {
263     free(values_link[i]);
264   }
265   return false;
266 }
267
268 /*
269  * Initialization of plugin AFTER parameters have been read
270  */
271 static bool
272 txtinfo_enable(void)
273 {
274   size_t i;
275
276   /* count static link keys */
277   while (keys_link[link_keys_static]) {
278     link_keys_static++;
279     link_keys_count++;
280   }
281
282   /* generate dynamic link keys */
283   for (i=1; i<olsr_get_linklabel_count(); i++) {
284     keys_link[link_keys_static + i - 1] = olsr_get_linklabel(i);
285     values_link[link_keys_static + i - 1] = olsr_malloc(LQTEXT_MAXLENGTH, "txtinfo linktemplate values");
286     link_keys_count++;
287   }
288   link_value_size = LQTEXT_MAXLENGTH;
289
290   /* generate link template */
291   strscpy(tmpl_link, "%localip%\t%neighip", sizeof(tmpl_link));
292   for (i=1; i<olsr_get_linklabel_count(); i++) {
293     strscat(tmpl_link, "%\t%", sizeof(tmpl_link));
294     strscat(tmpl_link, olsr_get_linklabel(i), sizeof(tmpl_link));
295   }
296   strscat(tmpl_link, "%\t%linkcost%\n", sizeof(tmpl_link));
297
298   /* generate link summary */
299   strscpy(headline_link, "Table: Links\nLocal IP\tRemote IP", sizeof(headline_link));
300   for (i=1; i<olsr_get_linklabel_count(); i++) {
301     strscat(headline_link, "\t", sizeof(headline_link));
302     strscat(headline_link, olsr_get_linklabel(i), sizeof(headline_link));
303   }
304   strscat(headline_link, "\t", sizeof(headline_link));
305   strscat(headline_link, olsr_get_linklabel(0), sizeof(headline_link));
306   strscat(headline_link, "\n", sizeof(headline_link));
307
308   for (i=0; i<ARRAYSIZE(commands); i++) {
309     commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
310     commands[i].cmd->acl = &allowed_nets;
311   }
312   return false;
313 }
314
315 static bool
316 txtinfo_exit(void) {
317   ip_acl_flush(&allowed_nets);
318   return false;
319 }
320
321 /**
322  * Parse user templates for \%, \n and \t
323  *
324  * @param template
325  */
326 static char *
327 parse_user_template(const char *template) {
328   // TODO: dynamic buffer ?
329   static char buffer[1024];
330   char *dst = buffer;
331
332   while (*template && (size_t)(dst - buffer) < sizeof(buffer)-1) {
333     if (*template == '\\') {
334       template++;
335       switch (*template) {
336         case 0:
337           *dst = 0;
338           break;
339         case 'n':
340           *dst = '\n';
341           break;
342         case 't':
343           *dst = '\t';
344           break;
345         case '\\':
346           *dst = '\\';
347           break;
348         default:
349           *dst++ = '\\';
350           *dst = *template;
351           break;
352       }
353     }
354     else {
355       *dst = *template;
356     }
357     template++;
358     dst++;
359   }
360   *dst = 0;
361   return buffer;
362 }
363
364 /**
365  * Callback for neigh command
366  */
367 static enum olsr_txtcommand_result
368 txtinfo_neigh(struct comport_connection *con,
369     const char *cmd __attribute__ ((unused)), const char *param)
370 {
371   struct nbr_entry *neigh;
372   struct list_iterator iterator;
373   const char *template;
374   int indexLength;
375
376   template = param != NULL ? parse_user_template(param) : tmpl_neigh;
377   if (param == NULL &&
378       abuf_puts(&con->out, "Table: Neighbors\nIP address\tSYM\tMPR\tMPRS\tWill.\t2 Hop Neighbors\n") < 0) {
379     return ABUF_ERROR;
380   }
381
382   if ((indexLength = abuf_template_init(keys_neigh, ARRAYSIZE(keys_neigh), template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
383     return ABUF_ERROR;
384   }
385
386   /* Neighbors */
387   OLSR_FOR_ALL_NBR_ENTRIES(neigh, iterator) {
388     olsr_ip_to_string(&buf_neighip, &neigh->nbr_addr);
389     strscpy(buf_sym, neigh->is_sym ? OLSR_YES : OLSR_NO, sizeof(buf_sym));
390     strscpy(buf_mrp, neigh->is_mpr ? OLSR_YES : OLSR_NO, sizeof(buf_mrp));
391     strscpy(buf_mprs, neigh->mprs_count>0 ? OLSR_YES : OLSR_NO, sizeof(buf_mprs));
392
393     snprintf(buf_willingness, sizeof(buf_willingness), "%d", neigh->willingness);
394     snprintf(buf_2hop, sizeof(buf_2hop), "%d", neigh->con_tree.count);
395
396     if (abuf_templatef(&con->out, template, values_neigh, tmpl_indices, indexLength) < 0) {
397         return ABUF_ERROR;
398     }
399   }
400
401   return CONTINUE;
402 }
403
404 /**
405  * Callback for link command
406  */
407 static enum olsr_txtcommand_result
408 txtinfo_link(struct comport_connection *con,
409     const char *cmd __attribute__ ((unused)), const char *param)
410 {
411   struct link_entry *lnk;
412   struct list_iterator iterator;
413   size_t i;
414   const char *template;
415   int indexLength;
416
417   template = param != NULL ? parse_user_template(param) : tmpl_link;
418   if (param == NULL) {
419     if (abuf_puts(&con->out, headline_link) < 0) {
420       return ABUF_ERROR;
421     }
422   }
423
424   if ((indexLength = abuf_template_init(keys_link, link_keys_count,
425       template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
426     return ABUF_ERROR;
427   }
428
429   /* Link set */
430   OLSR_FOR_ALL_LINK_ENTRIES(lnk, iterator) {
431     olsr_ip_to_string(&buf_localip, &lnk->local_iface_addr);
432     olsr_ip_to_string(&buf_neighip, &lnk->neighbor_iface_addr);
433     strscpy(buf_sym, lnk->status == SYM_LINK ? OLSR_YES : OLSR_NO, sizeof(buf_sym));
434     strscpy(buf_mrp, lnk->is_mpr ? OLSR_YES : OLSR_NO, sizeof(buf_mrp));
435     olsr_milli_to_txt(&buf_vtime, lnk->link_sym_timer == NULL ? 0 : lnk->link_sym_timer->timer_clock - now_times);
436     snprintf(buf_rawlinkcost, sizeof(buf_rawlinkcost), "%ud", lnk->linkcost);
437
438     olsr_get_linkcost_text(lnk->linkcost, false, buf_linkcost, sizeof(buf_linkcost));
439     for (i=1; i< olsr_get_linklabel_count(); i++) {
440       olsr_get_linkdata_text(lnk, i, values_link[link_keys_static + i - 1], link_value_size);
441     }
442
443     if (abuf_templatef(&con->out, template, values_link, tmpl_indices, indexLength) < 0) {
444         return ABUF_ERROR;
445     }
446   }
447
448   return CONTINUE;
449 }
450
451 /**
452  * Callback for routes command
453  */
454 static enum olsr_txtcommand_result
455 txtinfo_routes(struct comport_connection *con,
456     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
457 {
458   struct rt_entry *rt;
459   struct list_iterator iterator;
460   const char *template;
461   int indexLength;
462
463   template = param != NULL ? parse_user_template(param) : tmpl_routes;
464   if (param == NULL) {
465     if (abuf_appendf(&con->out, "Table: Routes\nDestination\tGateway IP\tMetric\t%s\tInterface\n",
466         olsr_get_linklabel(0)) < 0) {
467       return ABUF_ERROR;
468     }
469   }
470
471   if ((indexLength = abuf_template_init(keys_routes, ARRAYSIZE(keys_routes),
472       template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
473     return ABUF_ERROR;
474   }
475
476   /* Walk the route table */
477   OLSR_FOR_ALL_RT_ENTRIES(rt, iterator) {
478     if (!rt->rt_best) {
479       /* ignore entries without paths, they will be erased soon */
480       continue;
481     }
482     olsr_ip_prefix_to_string(&buf_destprefix, &rt->rt_dst);
483     olsr_ip_to_string(&buf_neighip, &rt->rt_best->rtp_nexthop.gateway);
484     snprintf(buf_hopcount, sizeof(buf_hopcount), "%d", rt->rt_best->rtp_metric.hops);
485     snprintf(buf_rawlinkcost, sizeof(buf_rawlinkcost), "%ud", rt->rt_best->rtp_metric.cost);
486     olsr_get_linkcost_text(rt->rt_best->rtp_metric.cost, true, buf_linkcost, sizeof(buf_linkcost));
487     strscpy(buf_interface,
488         rt->rt_best->rtp_nexthop.interface ? rt->rt_best->rtp_nexthop.interface->int_name : "[null]",
489         sizeof(buf_interface));
490
491     if (abuf_templatef(&con->out, template, values_routes, tmpl_indices, indexLength) < 0) {
492         return ABUF_ERROR;
493     }
494   }
495   return CONTINUE;
496 }
497
498 /**
499  * Callback for topology command
500  */
501 static enum olsr_txtcommand_result
502 txtinfo_topology(struct comport_connection *con,
503     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
504 {
505   struct tc_entry *tc;
506   struct list_iterator iterator, iterator2;
507   const char *template;
508   int indexLength;
509
510   template = param != NULL ? parse_user_template(param) : tmpl_topology;
511   if (param == NULL) {
512     if (abuf_appendf(&con->out, "Table: Topology\nDest. IP\tLast hop IP\tVirtual\t%s\n",
513         olsr_get_linklabel(0)) < 0) {
514       return ABUF_ERROR;
515     }
516   }
517
518   if ((indexLength = abuf_template_init(keys_topology, ARRAYSIZE(keys_topology),
519       template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
520     return ABUF_ERROR;
521   }
522
523   /* Topology */
524   OLSR_FOR_ALL_TC_ENTRIES(tc, iterator) {
525     struct tc_edge_entry *tc_edge;
526     olsr_ip_to_string(&buf_localip, &tc->addr);
527     if (tc->validity_timer) {
528       olsr_milli_to_txt(&buf_vtime, tc->validity_timer->timer_clock - now_times);
529     }
530     else {
531       strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
532     }
533
534     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge, iterator2) {
535       olsr_ip_to_string(&buf_neighip, &tc_edge->T_dest_addr);
536       strscpy(buf_virtual, tc_edge->virtual ? OLSR_YES : OLSR_NO, sizeof(buf_virtual));
537       if (tc_edge->virtual) {
538         buf_linkcost[0] = 0;
539         buf_rawlinkcost[0] = '0';
540         buf_rawlinkcost[1] = 0;
541       }
542       else {
543         snprintf(buf_rawlinkcost, sizeof(buf_rawlinkcost), "%ud", tc_edge->cost);
544         olsr_get_linkcost_text(tc_edge->cost, false, buf_linkcost, sizeof(buf_linkcost));
545       }
546
547       if (abuf_templatef(&con->out, template, values_topology, tmpl_indices, indexLength) < 0) {
548           return ABUF_ERROR;
549       }
550     }
551   }
552
553   return CONTINUE;
554 }
555
556 /**
557  * Callback for interfaces command
558  */
559 static enum olsr_txtcommand_result
560 txtinfo_interfaces(struct comport_connection *con,
561     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
562 {
563   const struct olsr_if_config *ifs;
564   const char *template;
565   int indexLength;
566
567   template = param != NULL ? parse_user_template(param) : tmpl_interface;
568   if (param == NULL) {
569     if (abuf_puts(&con->out, "Table: Interfaces\nName\tState\tMTU\tSrc-Adress\tDst-Adress\n") < 0) {
570       return ABUF_ERROR;
571     }
572   }
573
574   if ((indexLength = abuf_template_init(keys_interface, ARRAYSIZE(keys_interface),
575       template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
576     return ABUF_ERROR;
577   }
578
579
580   for (ifs = olsr_cnf->if_configs; ifs != NULL; ifs = ifs->next) {
581     const struct interface *const rifs = ifs->interf;
582
583     //prepare values
584     strscpy(buf_interface, ifs->name, sizeof(buf_interface));
585
586     if (!rifs) {
587       snprintf(buf_state, sizeof(buf_state), "DOWN");
588       snprintf(buf_mtu, sizeof(buf_mtu), "-");
589       snprintf(buf_srcip.buf, sizeof(buf_srcip.buf), "-");
590       snprintf(buf_dstip.buf, sizeof(buf_srcip.buf), "-");
591     } else {
592       snprintf(buf_mtu, sizeof(buf_mtu), "%d", rifs->int_mtu);
593       snprintf(buf_state, sizeof(buf_state), "UP");
594
595       if (olsr_cnf->ip_version == AF_INET){
596         ip4_to_string(&buf_srcip, rifs->int_src.v4.sin_addr);
597         ip4_to_string(&buf_dstip, rifs->int_multicast.v4.sin_addr);
598       } else {
599         ip6_to_string(&buf_srcip, &rifs->int_src.v6.sin6_addr);
600         ip6_to_string(&buf_dstip, &rifs->int_multicast.v6.sin6_addr); 
601       }
602     }
603
604     if (abuf_templatef(&con->out, template, 
605         values_interface, tmpl_indices, indexLength) < 0) {
606         return ABUF_ERROR;
607     }
608   }
609
610   return CONTINUE;
611 }
612
613 /**
614  * Callback for hna command
615  */
616 static enum olsr_txtcommand_result
617 txtinfo_hna(struct comport_connection *con,
618     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
619 {
620   const struct ip_prefix_entry *hna;
621   struct list_iterator iterator, iterator2;
622   struct tc_entry *tc;
623   const char *template;
624   int indexLength;
625
626   template = param != NULL ? parse_user_template(param) : tmpl_hna;
627   if (param == NULL) {
628     if (abuf_puts(&con->out, "Table: HNA\nDestination\tGateway\tvtime\n") < 0) {
629       return ABUF_ERROR;
630     }
631   }
632
633   if ((indexLength = abuf_template_init(keys_hna, ARRAYSIZE(keys_hna),
634       template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
635     return ABUF_ERROR;
636   }
637
638   /* Announced HNA entries */
639   OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna, iterator) {
640     olsr_ip_to_string(&buf_localip, &olsr_cnf->router_id);
641     olsr_ip_prefix_to_string(&buf_destprefix, &hna->net);
642     strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
643
644     if (abuf_templatef(&con->out, template, values_hna, tmpl_indices, indexLength) < 0) {
645         return ABUF_ERROR;
646     }
647   }
648
649   /* HNA entries */
650   OLSR_FOR_ALL_TC_ENTRIES(tc, iterator) {
651     struct hna_net *tmp_net;
652
653     olsr_ip_to_string(&buf_localip, &tc->addr);
654     if (tc->validity_timer) {
655       olsr_milli_to_txt(&buf_vtime, tc->validity_timer->timer_clock - now_times);
656     }
657     else {
658       strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
659     }
660
661     /* Check all networks */
662     OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net, iterator2) {
663       olsr_ip_prefix_to_string(&buf_destprefix, &tmp_net->hna_prefix);
664
665       if (abuf_templatef(&con->out, template, values_hna, tmpl_indices, indexLength) < 0) {
666           return ABUF_ERROR;
667       }
668     }
669   }
670
671   return CONTINUE;
672 }
673
674 /**
675  * Callback for mid command
676  */
677 static enum olsr_txtcommand_result
678 txtinfo_mid(struct comport_connection *con,
679     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
680 {
681   struct tc_entry *tc;
682   struct interface *interface;
683   struct list_iterator iterator, iterator2;
684
685   const char *template;
686   int indexLength;
687
688   template = param != NULL ? parse_user_template(param) : tmpl_mid;
689   if (param == NULL) {
690     if (abuf_puts(&con->out, "Table: MID\nIP address\tAliases\tvtime\n") < 0) {
691       return ABUF_ERROR;
692     }
693   }
694
695   if ((indexLength = abuf_template_init(keys_mid, ARRAYSIZE(keys_mid),
696       template, tmpl_indices, ARRAYSIZE(tmpl_indices))) < 0) {
697     return ABUF_ERROR;
698   }
699
700   OLSR_FOR_ALL_INTERFACES(interface, iterator) {
701     if (olsr_ipcmp(&olsr_cnf->router_id, &interface->ip_addr) != 0) {
702       olsr_ip_to_string(&buf_localip, &olsr_cnf->router_id);
703       olsr_ip_to_string(&buf_aliasip, &interface->ip_addr);
704       strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
705
706       if (abuf_templatef(&con->out, template, values_mid, tmpl_indices, indexLength) < 0) {
707           return ABUF_ERROR;
708       }
709     }
710   }
711
712   /* MID root is the TC entry */
713   OLSR_FOR_ALL_TC_ENTRIES(tc, iterator) {
714     struct mid_entry *alias;
715
716     olsr_ip_to_string(&buf_localip, &tc->addr);
717     if (tc->validity_timer) {
718       if (tc->validity_timer) {
719         olsr_milli_to_txt(&buf_vtime, tc->validity_timer->timer_clock - now_times);
720       }
721       else {
722         strscpy(buf_vtime.buf, "0.0", sizeof(buf_vtime));
723       }
724
725       OLSR_FOR_ALL_TC_MID_ENTRIES(tc, alias, iterator2) {
726         olsr_ip_to_string(&buf_aliasip, &alias->mid_alias_addr);
727
728         if (abuf_templatef(&con->out, template, values_mid, tmpl_indices, indexLength) < 0) {
729           return ABUF_ERROR;
730         }
731       }
732     }
733   }
734   return CONTINUE;
735 }
736
737 /*
738  * Local Variables:
739  * mode: c
740  * style: linux
741  * c-basic-offset: 4
742  * indent-tabs-mode: nil
743  * End:
744  */