httpinfo: show the scaled gw cost in the sgw pane
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
1
2 /*
3  * HTTP Info plugin for the olsr.org OLSR daemon
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
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
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #ifdef _WIN32
52 #include <io.h>
53 #else /* _WIN32 */
54 #include <netdb.h>
55 #endif /* _WIN32 */
56
57 #include "olsr.h"
58 #include "builddata.h"
59 #include "olsr_cfg.h"
60 #include "interfaces.h"
61 #include "gateway.h"
62 #include "gateway_costs.h"
63 #include "olsr_protocol.h"
64 #include "net_olsr.h"
65 #include "link_set.h"
66 #include "ipcalc.h"
67 #include "lq_plugin.h"
68 #include "common/autobuf.h"
69 #ifdef HTTPINFO_PUD
70   #include <pud/src/receiver.h>
71   #include <pud/src/pud.h>
72   #include <nmea/info.h>
73   #include <nmea/sentence.h>
74 #endif /* HTTPINFO_PUD */
75
76 #include "olsrd_httpinfo.h"
77 #include "admin_interface.h"
78 #include "gfx.h"
79
80 #ifdef OS
81 #undef OS
82 #endif /* OS */
83
84 #ifdef _WIN32
85 #define close(x) closesocket(x)
86 #define OS "Windows"
87 #endif /* _WIN32 */
88 #ifdef __linux__
89 #define OS "GNU/Linux"
90 #endif /* __linux__ */
91 #if defined __FreeBSD__ || defined __FreeBSD_kernel__
92 #define OS "FreeBSD"
93 #endif /* defined __FreeBSD__ || defined __FreeBSD_kernel__ */
94
95 #ifndef OS
96 #define OS "Undefined"
97 #endif /* OS */
98
99 #define MAX_CLIENTS 3
100
101 #define MAX_HTTPREQ_SIZE (1024 * 10)
102
103 #define DEFAULT_TCP_PORT 1978
104
105 #define HTML_BUFSIZE (1024 * 4000)
106
107 #define FRAMEWIDTH (resolve_ip_addresses ? 900 : 800)
108
109 #define FILENREQ_MATCH(req, filename) \
110         !strcmp(req, filename) || \
111         (strlen(req) && !strcmp(&req[1], filename))
112
113 static const char httpinfo_css[] =
114   "#A {text-decoration: none}\n" "TH{text-align: left}\n" "H1, H3, TD, TH {font-family: Helvetica; font-size: 80%}\n"
115   "h2\n {\nfont-family: Helvetica;\n font-size: 14px;text-align: center;\n"
116   "line-height: 16px;\ntext-decoration: none;\nborder: 1px solid #ccc;\n" "margin: 5px;\nbackground: #ececec;\n}\n"
117   "hr\n{\nborder: none;\npadding: 1px;\nbackground: url(grayline.gif) repeat-x bottom;\n}\n"
118   "#maintable\n{\nmargin: 0px;\npadding: 5px;\nborder-left: 1px solid #ccc;\n"
119   "border-right: 1px solid #ccc;\nborder-bottom: 1px solid #ccc;\n}\n"
120   "#footer\n{\nfont-size: 10px;\nline-height: 14px;\ntext-decoration: none;\ncolor: #666;\n}\n"
121   "#hdr\n{\nfont-size: 14px;\ntext-align: center;\nline-height: 16px;\n" "text-decoration: none;\nborder: 1px solid #ccc;\n"
122   "margin: 5px;\nbackground: #ececec;\n}\n"
123   "#container\n{\nwidth: 1000px;\npadding: 30px;\nborder: 1px solid #ccc;\nbackground: #fff;\n}\n"
124   "#tabnav\n{\nheight: 20px;\nmargin: 0;\npadding-left: 10px;\n" "background: url(grayline.gif) repeat-x bottom;\n}\n"
125   "#tabnav li\n{\nmargin: 0;\npadding: 0;\ndisplay: inline;\nlist-style-type: none;\n}\n"
126   "#tabnav a:link, #tabnav a:visited\n{\nfloat: left;\nbackground: #ececec;\n"
127   "font-size: 12px;\nline-height: 14px;\nfont-weight: bold;\npadding: 2px 10px 2px 10px;\n"
128   "margin-right: 4px;\nborder: 1px solid #ccc;\ntext-decoration: none;\ncolor: #777;\n}\n"
129   "#tabnav a:link.active, #tabnav a:visited.active\n{\nborder-bottom: 1px solid #fff;\n" "background: #ffffff;\ncolor: #000;\n}\n"
130   "#tabnav a:hover\n{\nbackground: #777777;\ncolor: #ffffff;\n}\n"
131   ".input_text\n{\nbackground: #E5E5E5;\nmargin-left: 5px; margin-top: 0px;\n"
132   "text-align: left;\n\nwidth: 100px;\npadding: 0px;\ncolor: #000000;\n"
133   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #ccc;\n}\n"
134   ".input_button\n{\nbackground: #B5D1EE;\nmargin-left: 5px;\nmargin-top: 0px;\n"
135   "text-align: center;\nwidth: 120px;\npadding: 0px;\ncolor: #000000;\n"
136   "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #000;\n}\n";
137
138 typedef void (*build_body_callback) (struct autobuf *);
139
140 struct tab_entry {
141   const char *tab_label;
142   const char *filename;
143   build_body_callback build_body_cb;
144   bool display_tab;
145 };
146
147 struct static_bin_file_entry {
148   const char *filename;
149   unsigned char *data;
150   unsigned int data_size;
151 };
152
153 struct static_txt_file_entry {
154   const char *filename;
155   const char *data;
156 };
157
158 struct dynamic_file_entry {
159   const char *filename;
160   int (*process_data_cb) (char *, uint32_t, char *, uint32_t);
161 };
162
163 static int get_http_socket(int);
164
165 static void build_tabs(struct autobuf *, int);
166
167 static void parse_http_request(int fd, void *, unsigned int);
168
169 static int build_http_header(http_header_type, bool, uint32_t, char *, uint32_t);
170
171 static void build_frame(struct autobuf *, const char *, const char *, int, build_body_callback frame_body_cb);
172
173 static void build_routes_body(struct autobuf *);
174
175 static void build_config_body(struct autobuf *);
176
177 static void build_neigh_body(struct autobuf *);
178
179 static void build_topo_body(struct autobuf *);
180
181 static void build_mid_body(struct autobuf *);
182
183 static void build_nodes_body(struct autobuf *);
184
185 static void build_all_body(struct autobuf *);
186
187 #ifdef __linux__
188 static void build_sgw_body(struct autobuf *);
189 #endif /* __linux__ */
190
191 #ifdef HTTPINFO_PUD
192 static void build_pud_body(struct autobuf *);
193 #endif /* HTTPINFO_PUD */
194
195 static void build_about_body(struct autobuf *);
196
197 static void build_cfgfile_body(struct autobuf *);
198
199 static int check_allowed_ip(const struct allowed_net *const /*allowed_nets*/, const union olsr_ip_addr *const /*addr*/);
200
201 static void build_ip_txt(struct autobuf *, const bool want_link, const char *const ipaddrstr, const int prefix_len);
202
203 static void build_ipaddr_link(struct autobuf *, const bool want_link, const union olsr_ip_addr *const ipaddr,
204                              const int prefix_len);
205 static void section_title(struct autobuf *, const char *title);
206
207 static void httpinfo_write_data(void *foo);
208
209 static struct timeval start_time;
210 static struct http_stats stats;
211 static int http_socket;
212
213 static char *outbuffer[MAX_CLIENTS];
214 static size_t outbuffer_size[MAX_CLIENTS];
215 static size_t outbuffer_written[MAX_CLIENTS];
216 static int outbuffer_socket[MAX_CLIENTS];
217 static int outbuffer_count;
218
219 static struct timer_entry *writetimer_entry;
220
221 static const struct tab_entry tab_entries[] = {
222   {"Configuration", "config", build_config_body, true},
223   {"Routes", "routes", build_routes_body, true},
224   {"Links/Topology", "nodes", build_nodes_body, true},
225 #ifdef __linux__
226   {"Smart Gateway", "sgw", build_sgw_body, true},
227 #endif /* __linux__ */
228 #ifdef HTTPINFO_PUD
229   {"Position", "position", build_pud_body, true},
230 #endif /* HTTPINFO_PUD */
231   {"All", "all", build_all_body, true},
232 #ifdef ADMIN_INTERFACE
233   {"Admin", "admin", build_admin_body, true},
234 #endif /* ADMIN_INTERFACE */
235   {"About", "about", build_about_body, true},
236   {"FOO", "cfgfile", build_cfgfile_body, false},
237   {NULL, NULL, NULL, false}
238 };
239
240 static const struct static_bin_file_entry static_bin_files[] = {
241   {"favicon.ico", favicon_ico, sizeof(favicon_ico)}
242   ,
243   {"logo.gif", logo_gif, sizeof(logo_gif)}
244   ,
245   {"grayline.gif", grayline_gif, sizeof(grayline_gif)}
246   ,
247   {NULL, NULL, 0}
248 };
249
250 static const struct static_txt_file_entry static_txt_files[] = {
251   {"httpinfo.css", httpinfo_css},
252   {NULL, NULL}
253 };
254
255 #ifdef ADMIN_INTERFACE
256 static const struct dynamic_file_entry dynamic_files[] = {
257   {"set_values", process_set_values},
258   {NULL, NULL}
259 };
260 #endif /* ADMIN_INTERFACE */
261
262 static int
263 get_http_socket(int port)
264 {
265   struct sockaddr_in sock_in;
266   uint32_t yes = 1;
267
268   /* Init ipc socket */
269   int s = socket(AF_INET, SOCK_STREAM, 0);
270   if (s == -1) {
271     olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
272     return -1;
273   }
274
275   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
276     olsr_printf(1, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
277     close(s);
278     return -1;
279   }
280
281   /* Bind the socket */
282
283   /* complete the socket structure */
284   memset(&sock_in, 0, sizeof(sock_in));
285   sock_in.sin_family = AF_INET;
286   sock_in.sin_addr.s_addr = httpinfo_listen_ip.v4.s_addr;
287   sock_in.sin_port = htons(port);
288
289   /* bind the socket to the port number */
290   if (bind(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) == -1) {
291     olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
292     close(s);
293     return -1;
294   }
295
296   /* show that we are willing to listen */
297   if (listen(s, 1) == -1) {
298     olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
299     close(s);
300     return -1;
301   }
302
303   return s;
304 }
305
306 /**
307  *Do initialization here
308  *
309  *This function is called by the my_init
310  *function in uolsrd_plugin.c
311  */
312 int
313 olsrd_plugin_init(void)
314 {
315   /* Get start time */
316   gettimeofday(&start_time, NULL);
317
318   /* set up HTTP socket */
319   http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
320
321   if (http_socket < 0) {
322     olsr_exit("HTTPINFO: could not initialize HTTP socket", EXIT_FAILURE);
323   }
324
325   /* Register socket */
326   add_olsr_socket(http_socket, &parse_http_request, NULL, NULL, SP_PR_READ);
327
328   return 1;
329 }
330
331 /* Non reentrant - but we are not multithreaded anyway */
332 static void
333 parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
334 {
335   struct sockaddr_in pin;
336   struct autobuf body_abuf = { 0, 0, NULL };
337   socklen_t addrlen;
338   char header_buf[MAX_HTTPREQ_SIZE];
339   char req_type[11];
340   char filename[251];
341   char http_version[11];
342   int client_socket;
343   size_t header_length = 0;
344   size_t c = 0;
345   int r = 1;
346 #ifdef __linux__
347   struct timeval timeout = { 0, 200 };
348 #endif /* __linux__ */
349
350   if (outbuffer_count >= MAX_CLIENTS) {
351     olsr_printf(1, "(HTTPINFO) maximum number of connection reached\n");
352     return;
353   }
354
355   addrlen = sizeof(struct sockaddr_in);
356   client_socket = accept(fd, (struct sockaddr *)&pin, &addrlen);
357   if (client_socket == -1) {
358     olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
359     goto close_connection;
360   }
361
362 #ifdef __linux__
363   if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
364     olsr_printf(1, "(HTTPINFO)SO_RCVTIMEO failed %s\n", strerror(errno));
365     goto close_connection;
366   }
367
368   if (setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
369     olsr_printf(1, "(HTTPINFO)SO_SNDTIMEO failed %s\n", strerror(errno));
370     goto close_connection;
371   }
372 #endif /* __linux__ */
373   if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
374     struct ipaddr_str strbuf;
375     olsr_printf(0, "HTTP request from non-allowed host %s!\n",
376                 olsr_ip_to_string(&strbuf, (union olsr_ip_addr *)&pin.sin_addr.s_addr));
377     goto close_connection;
378   }
379
380   memset(header_buf, 0, sizeof(header_buf));
381
382   while ((r = recv(client_socket, &header_buf[c], 1, 0)) > 0 && (c < sizeof(header_buf) - 1)) {
383     c++;
384
385     if ((c > 3 && !strcmp(&header_buf[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&header_buf[c - 2], "\n\n")))
386       break;
387   }
388
389   if (r < 0) {
390     olsr_printf(1, "(HTTPINFO) Failed to receive data from client!\n");
391     stats.err_hits++;
392     goto close_connection;
393   }
394
395   /* Get the request */
396   if (sscanf(header_buf, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
397     /* Try without HTTP version */
398     if (sscanf(header_buf, "%10s %250s\n", req_type, filename) != 2) {
399       olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", header_buf);
400       stats.err_hits++;
401       goto close_connection;
402     }
403   }
404
405   olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
406   abuf_init(&body_abuf, 102400);
407
408   if (!strcmp(req_type, "POST")) {
409 #ifdef ADMIN_INTERFACE
410     int i = 0;
411     while (dynamic_files[i].filename) {
412       printf("POST checking %s\n", dynamic_files[i].filename);
413       if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
414         uint32_t param_size;
415
416         stats.ok_hits++;
417
418         param_size = recv(client_sockets[curr_clients], header_buf, sizeof(header_buf) - 1, 0);
419
420         header_buf[param_size] = '\0';
421         printf("Dynamic read %d bytes\n", param_size);
422
423         //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
424         body_length += dynamic_files[i].process_data_cb(header_buf, param_size, &body_buf[body_length], sizeof(body_buf) - body_length);
425         header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
426         goto send_http_data;
427       }
428       i++;
429     }
430 #endif /* ADMIN_INTERFACE */
431     /* We only support GET */
432     abuf_puts(&body_abuf, HTTP_400_MSG);
433     stats.ill_hits++;
434     header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
435   } else if (!strcmp(req_type, "GET")) {
436     int i = 0;
437
438     for (i = 0; static_bin_files[i].filename; i++) {
439       if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
440         break;
441       }
442     }
443
444     if (static_bin_files[i].filename) {
445       stats.ok_hits++;
446       abuf_memcpy(&body_abuf, static_bin_files[i].data, static_bin_files[i].data_size);
447       header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
448       goto send_http_data;
449     }
450
451     i = 0;
452     while (static_txt_files[i].filename) {
453       if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
454         break;
455       }
456       i++;
457     }
458
459     if (static_txt_files[i].filename) {
460       stats.ok_hits++;
461       abuf_puts(&body_abuf, static_txt_files[i].data);
462       header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
463       goto send_http_data;
464     }
465
466     i = 0;
467     if (strlen(filename) > 1) {
468       while (tab_entries[i].filename) {
469         if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
470           break;
471         }
472         i++;
473       }
474     }
475
476     if (tab_entries[i].filename) {
477 #ifdef NETDIRECT
478       header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
479       r = send(client_sockets[curr_clients], header_buf, header_length, 0);
480       if (r < 0) {
481         olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
482         goto close_connection;
483       }
484       netsprintf_error = 0;
485       netsprintf_direct = 1;
486 #endif /* NETDIRECT */
487       abuf_appendf(&body_abuf,
488                  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<head>\n"
489                  "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
490                  "<title>olsr.org httpinfo plugin</title>\n" "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
491                  "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
492                  "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n" "</head>\n"
493                  "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
494                  "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
495                  "<tbody><tr bgcolor=\"#ffffff\">\n" "<td align=\"left\" height=\"69\" valign=\"middle\" width=\"80%%\">\n"
496                  "<font color=\"black\" face=\"timesroman\" size=\"6\">&nbsp;&nbsp;&nbsp;<a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
497                  "<td height=\"69\" valign=\"middle\" width=\"20%%\">\n"
498                  "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n" "</tr>\n"
499                  "</tbody>\n" "</table>\n", FRAMEWIDTH);
500
501       build_tabs(&body_abuf, i);
502       build_frame(&body_abuf, "Current Routes", "routes", FRAMEWIDTH, tab_entries[i].build_body_cb);
503
504       stats.ok_hits++;
505
506       abuf_appendf(&body_abuf,
507                  "</table>\n" "<div id=\"footer\">\n" "<center>\n" "(C)2005 Andreas T&oslash;nnesen<br/>\n"
508                  "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
509
510 #ifdef NETDIRECT
511       netsprintf_direct = 1;
512       goto close_connection;
513 #else /* NETDIRECT */
514       header_length = build_http_header(HTTP_OK, true, body_abuf.len, header_buf, sizeof(header_buf));
515       goto send_http_data;
516 #endif /* NETDIRECT */
517     }
518
519     stats.ill_hits++;
520     abuf_puts(&body_abuf, HTTP_404_MSG);
521     header_length = build_http_header(HTTP_BAD_FILE, true, body_abuf.len, header_buf, sizeof(header_buf));
522   } else {
523     /* We only support GET */
524     abuf_puts(&body_abuf, HTTP_404_MSG);
525     stats.ill_hits++;
526     header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
527   }
528
529 send_http_data:
530   if (header_length + body_abuf.len > 0) {
531     outbuffer[outbuffer_count] = olsr_malloc(header_length + body_abuf.len, "http output buffer");
532     outbuffer_size[outbuffer_count] = header_length + body_abuf.len;
533     outbuffer_written[outbuffer_count] = 0;
534     outbuffer_socket[outbuffer_count] = client_socket;
535
536     memcpy(outbuffer[outbuffer_count], header_buf, header_length);
537     if (body_abuf.len > 0) {
538       memcpy((outbuffer[outbuffer_count]) + header_length, body_abuf.buf, body_abuf.len);
539     }
540     outbuffer_count++;
541
542     if (outbuffer_count == 1) {
543       writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &httpinfo_write_data, NULL, 0);
544     }
545   }
546   abuf_free(&body_abuf);
547   /*
548    * client_socket is stored in outbuffer_socket[outbuffer_count] and closed
549    * by the httpinfo_write_data timer callback, so don't close it here
550    */
551   return;
552
553 close_connection:
554   abuf_free(&body_abuf);
555   if (client_socket >= 0) {
556     close(client_socket);
557   }
558 }
559
560 static void
561 httpinfo_write_data(void *foo __attribute__ ((unused))) {
562   fd_set set;
563   int result, i, j, max;
564   struct timeval tv;
565
566   FD_ZERO(&set);
567   max = 0;
568   for (i=0; i<outbuffer_count; i++) {
569     /* prevent warning in win32 */
570     FD_SET((unsigned int)outbuffer_socket[i], &set);
571     if (outbuffer_socket[i] > max) {
572       max = outbuffer_socket[i];
573     }
574   }
575
576   tv.tv_sec = 0;
577   tv.tv_usec = 0;
578
579   result = select(max + 1, NULL, &set, NULL, &tv);
580   if (result <= 0) {
581     return;
582   }
583
584   for (i=0; i<outbuffer_count; i++) {
585     if (FD_ISSET(outbuffer_socket[i], &set)) {
586       result = write(outbuffer_socket[i], outbuffer[i] + outbuffer_written[i], outbuffer_size[i] - outbuffer_written[i]);
587       if (result > 0) {
588         outbuffer_written[i] += result;
589       }
590
591       if (result <= 0 || outbuffer_written[i] == outbuffer_size[i]) {
592         /* close this socket and cleanup*/
593         close(outbuffer_socket[i]);
594         free (outbuffer[i]);
595
596         for (j=i+1; j<outbuffer_count; j++) {
597           outbuffer[j-1] = outbuffer[j];
598           outbuffer_size[j-1] = outbuffer_size[j];
599           outbuffer_socket[j-1] = outbuffer_socket[j];
600           outbuffer_written[j-1] = outbuffer_written[j];
601         }
602         outbuffer_count--;
603       }
604     }
605   }
606   if (outbuffer_count == 0) {
607     olsr_stop_timer(writetimer_entry);
608   }
609 }
610
611 int
612 build_http_header(http_header_type type, bool is_html, uint32_t msgsize, char *buf, uint32_t bufsize)
613 {
614   time_t currtime;
615   const char *h;
616   int size;
617
618   switch (type) {
619   case HTTP_BAD_REQ:
620     h = HTTP_400;
621     break;
622   case HTTP_BAD_FILE:
623     h = HTTP_404;
624     break;
625   default:
626     /* Defaults to OK */
627     h = HTTP_200;
628     break;
629   }
630   size = snprintf(buf, bufsize, "%s", h);
631
632   /* Date */
633   time(&currtime);
634   size += strftime(&buf[size], bufsize - size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
635
636   /* Server version */
637   size += snprintf(&buf[size], bufsize - size, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
638
639   /* connection-type */
640   size += snprintf(&buf[size], bufsize - size, "Connection: closed\r\n");
641
642   /* MIME type */
643   size += snprintf(&buf[size], bufsize - size, "Content-type: text/%s\r\n", is_html ? "html" : "plain");
644
645   /* Content length */
646   if (msgsize > 0) {
647     size += snprintf(&buf[size], bufsize - size, "Content-length: %i\r\n", msgsize);
648   }
649
650   /* Cache-control
651    * No caching dynamic pages
652    */
653   size += snprintf(&buf[size], bufsize - size, "Cache-Control: no-cache\r\n");
654
655   if (!is_html) {
656     size += snprintf(&buf[size], bufsize - size, "Accept-Ranges: bytes\r\n");
657   }
658   /* End header */
659   size += snprintf(&buf[size], bufsize - size, "\r\n");
660
661   olsr_printf(1, "HEADER:\n%s", buf);
662
663   return size;
664 }
665
666 static void
667 build_tabs(struct autobuf *abuf, int active)
668 {
669   int tabs = 0;
670
671   abuf_appendf(abuf,
672       "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
673       "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
674   for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
675     if (!tab_entries[tabs].display_tab) {
676       continue;
677     }
678     abuf_appendf(abuf, "<li><a href=\"%s\"%s>%s</a></li>\n", tab_entries[tabs].filename,
679                tabs == active ? " class=\"active\"" : "", tab_entries[tabs].tab_label);
680   }
681   abuf_appendf(abuf, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
682 }
683
684 /*
685  * destructor - called at unload
686  */
687 void
688 olsr_plugin_exit(void)
689 {
690   struct allowed_net *a, *next;
691   if (http_socket >= 0) {
692     CLOSE(http_socket);
693   }
694
695   for (a = allowed_nets; a != NULL; a = next) {
696     next = a->next;
697
698     free(a);
699   }
700 }
701
702 static void
703 section_title(struct autobuf *abuf, const char *title)
704 {
705   abuf_appendf(abuf,
706                   "<h2>%s</h2>\n" "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n",
707                   title);
708 }
709
710 static void
711 build_frame(struct autobuf *abuf, const char *title __attribute__ ((unused)), const char *the_link
712             __attribute__ ((unused)), int width __attribute__ ((unused)), build_body_callback frame_body_cb)
713 {
714   abuf_puts(abuf, "<div id=\"maintable\">\n");
715   frame_body_cb(abuf);
716   abuf_puts(abuf, "</div>\n");
717 }
718
719 static void
720 fmt_href(struct autobuf *abuf, const char *const ipaddr)
721 {
722   abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
723 }
724
725 static void
726 build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
727 {
728   if (print_link) {
729     fmt_href(abuf, ipaddrstr);
730   }
731
732   abuf_puts(abuf, ipaddrstr);
733   /* print ip address or ip prefix ? */
734   if (prefix_len != -1 && prefix_len != olsr_cnf->maxplen) {
735     abuf_appendf(abuf, "/%d", prefix_len);
736   }
737
738   if (print_link) {             /* Print the link only if there is no prefix_len */
739     abuf_puts(abuf, "</a>");
740   }
741 }
742
743 static void
744 build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr,
745                   const int prefix_len)
746 {
747   struct ipaddr_str ipaddrstr;
748   const struct hostent *const hp =
749 #ifndef _WIN32
750     resolve_ip_addresses ? gethostbyaddr((const void *)ipaddr, olsr_cnf->ipsize,
751                                          olsr_cnf->ip_version) :
752 #endif /* _WIN32 */
753     NULL;
754   /* Print the link only if there is no prefix_len and ip_version is AF_INET */
755   const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen) && (olsr_cnf->ip_version == AF_INET);
756   olsr_ip_to_string(&ipaddrstr, ipaddr);
757
758   abuf_puts(abuf, "<td>");
759   build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
760   abuf_puts(abuf, "</td>");
761
762   if (resolve_ip_addresses) {
763     if (hp) {
764       abuf_puts(abuf, "<td>(");
765       if (print_link) {
766         fmt_href(abuf, ipaddrstr.buf);
767       }
768       abuf_puts(abuf, hp->h_name);
769       if (print_link) {
770         abuf_puts(abuf, "</a>");
771       }
772       abuf_puts(abuf, ")</td>");
773     } else {
774       abuf_puts(abuf, "<td/>");
775     }
776   }
777 }
778
779 #define build_ipaddr_with_link(buf, ipaddr, plen) \
780           build_ipaddr_link((buf), true, (ipaddr), (plen))
781 #define build_ipaddr_no_link(buf, ipaddr, plen) \
782           build_ipaddr_link((buf), false, (ipaddr), (plen))
783
784 static void
785 build_route(struct autobuf *abuf, const struct rt_entry *rt)
786 {
787   struct lqtextbuffer lqbuffer;
788
789   abuf_puts(abuf, "<tr>");
790   build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
791   build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
792
793   abuf_appendf(abuf, "<td>%d</td>", rt->rt_best->rtp_metric.hops);
794   abuf_appendf(abuf, "<td>%s</td>",
795              get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
796   abuf_appendf(abuf, "<td>%s</td></tr>\n",
797              if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
798 }
799
800 static void
801 build_routes_body(struct autobuf *abuf)
802 {
803   struct rt_entry *rt;
804   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
805   section_title(abuf, "OLSR Routes in Kernel");
806   abuf_appendf(abuf,
807              "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
808              colspan, colspan);
809
810   /* Walk the route table */
811   OLSR_FOR_ALL_RT_ENTRIES(rt) {
812     build_route(abuf, rt);
813   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
814
815   abuf_puts(abuf, "</table>\n");
816 }
817
818 static void
819 build_config_body(struct autobuf *abuf)
820 {
821   const struct olsr_if *ifs;
822   const struct plugin_entry *pentry;
823   const struct plugin_param *pparam;
824   struct ipaddr_str mainaddrbuf;
825
826   abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
827   abuf_appendf(abuf, "OS: %s\n<br>", OS);
828
829   {
830     const time_t currtime = time(NULL);
831
832     abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>",
833                             localtime(&currtime));
834   }
835
836   {
837     struct timeval now, uptime;
838     int hours, mins, days;
839     gettimeofday(&now, NULL);
840     timersub(&now, &start_time, &uptime);
841
842     days = uptime.tv_sec / 86400;
843     uptime.tv_sec %= 86400;
844     hours = uptime.tv_sec / 3600;
845     uptime.tv_sec %= 3600;
846     mins = uptime.tv_sec / 60;
847     uptime.tv_sec %= 60;
848
849     abuf_puts(abuf, "Olsrd uptime: <em>");
850     if (days) {
851       abuf_appendf(abuf, "%d day(s) ", days);
852     }
853     abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
854   }
855
856   abuf_appendf(abuf, "HTTP stats(ok/dyn/error/illegal): <em>%d/%d/%d/%d</em><br>\n", stats.ok_hits,
857              stats.dyn_hits, stats.err_hits, stats.ill_hits);
858
859   abuf_puts(abuf,
860              "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
861
862   abuf_puts(abuf, "<h2>Variables</h2>\n");
863
864   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
865
866   abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n",
867              olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
868   abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
869   abuf_appendf(abuf, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
870   abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n", FIB_METRIC_TXT[olsr_cnf->fib_metric]);
871
872   abuf_puts(abuf, "</tr>\n<tr>\n");
873
874   abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", (double)olsr_cnf->pollrate);
875   abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
876   abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
877   abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", (double)olsr_cnf->lq_nat_thresh);
878
879   abuf_puts(abuf, "</tr>\n<tr>\n");
880
881   abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
882   abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
883   abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rt_table, olsr_cnf->rt_table);
884   abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rt_table_default,
885              olsr_cnf->rt_table_default);
886   abuf_appendf(abuf, "<td>RtTableTunnel: 0x%04x/%d</td>\n", olsr_cnf->rt_table_tunnel,
887              olsr_cnf->rt_table_tunnel);
888   abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness,
889              olsr_cnf->willingness_auto ? "(auto)" : "");
890
891   if (olsr_cnf->lq_level == 0) {
892     abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
893                olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
894     if (olsr_cnf->use_hysteresis) {
895       abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", (double)olsr_cnf->hysteresis_param.scaling);
896       abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", (double)olsr_cnf->hysteresis_param.thr_low,
897                   (double)olsr_cnf->hysteresis_param.thr_high);
898     }
899   }
900
901   abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>LQ extension: %s</td>\n",
902              olsr_cnf->lq_level ? "Enabled" : "Disabled");
903   if (olsr_cnf->lq_level) {
904     abuf_appendf(abuf, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
905                 (double)olsr_cnf->lq_aging);
906   }
907   abuf_puts(abuf, "</tr></table>\n");
908
909   abuf_puts(abuf, "<h2>Interfaces</h2>\n");
910   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
911   for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
912     const struct interface_olsr *const rifs = ifs->interf;
913     abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
914     if (!rifs) {
915       abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
916       continue;
917     }
918
919     if (olsr_cnf->ip_version == AF_INET) {
920       struct ipaddr_str addrbuf, maskbuf, bcastbuf;
921       abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MASK: %s</td>\n" "<td>BCAST: %s</td>\n" "</tr>\n",
922                  ip4_to_string(&addrbuf, rifs->int_addr.sin_addr), ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
923                  ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
924     } else {
925       struct ipaddr_str addrbuf, maskbuf;
926       abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MCAST: %s</td>\n" "<td></td>\n" "</tr>\n",
927                  ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
928     }
929     abuf_appendf(abuf, "<tr>\n" "<td>MTU: %d</td>\n" "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n",
930                rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
931   }
932   abuf_puts(abuf, "</table>\n");
933
934   abuf_appendf(abuf, "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
935              olsr_cnf->allow_no_interfaces ? "run even" : "halt");
936
937   abuf_puts(abuf, "<h2>Plugins</h2>\n");
938   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
939   for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
940     abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
941
942     for (pparam = pentry->params; pparam; pparam = pparam->next) {
943       abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
944     }
945     abuf_puts(abuf, "</select></td></tr>\n");
946
947   }
948   abuf_puts(abuf, "</table>\n");
949
950   section_title(abuf, "Announced HNA entries");
951   if (olsr_cnf->hna_entries) {
952     struct ip_prefix_list *hna;
953     abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
954     for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
955       struct ipaddr_str netbuf;
956       abuf_appendf(abuf, "<tr><td>%s/%d</td></tr>\n", olsr_ip_to_string(&netbuf, &hna->net.prefix),
957                  hna->net.prefix_len);
958     }
959   } else {
960     abuf_puts(abuf, "<tr><td></td></tr>\n");
961   }
962   abuf_puts(abuf, "</table>\n");
963 }
964
965 static void
966 build_neigh_body(struct autobuf *abuf)
967 {
968   struct neighbor_entry *neigh;
969   struct link_entry *the_link = NULL;
970   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
971
972   section_title(abuf, "Links");
973
974   abuf_appendf(abuf,
975              "<tr><th%s>Local IP</th><th%s>Remote IP</th><th>Hysteresis</th>",
976              colspan, colspan);
977   if (olsr_cnf->lq_level > 0) {
978     abuf_puts(abuf, "<th>LinkCost</th>");
979   }
980   abuf_puts(abuf, "</tr>\n");
981
982   /* Link set */
983   OLSR_FOR_ALL_LINK_ENTRIES(the_link) {
984     abuf_puts(abuf, "<tr>");
985     build_ipaddr_with_link(abuf, &the_link->local_iface_addr, -1);
986     build_ipaddr_with_link(abuf, &the_link->neighbor_iface_addr, -1);
987     abuf_appendf(abuf, "<td>%0.2f</td>", (double)the_link->L_link_quality);
988     if (olsr_cnf->lq_level > 0) {
989       struct lqtextbuffer lqbuffer1, lqbuffer2;
990       abuf_appendf(abuf, "<td>(%s) %s</td>", get_link_entry_text(the_link, '/', &lqbuffer1),
991                  get_linkcost_text(the_link->linkcost, false, &lqbuffer2));
992     }
993     abuf_puts(abuf, "</tr>\n");
994   } OLSR_FOR_ALL_LINK_ENTRIES_END(the_link);
995
996   abuf_puts(abuf, "</table>\n");
997
998   section_title(abuf, "Neighbors");
999   abuf_appendf(abuf,
1000              "<tr><th%s>IP Address</th><th>SYM</th><th>MPR</th><th>MPRS</th><th>Willingness</th><th>2 Hop Neighbors</th></tr>\n",
1001              colspan);
1002   /* Neighbors */
1003   OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
1004
1005     struct neighbor_2_list_entry *list_2;
1006     int thop_cnt;
1007     abuf_puts(abuf, "<tr>");
1008     build_ipaddr_with_link(abuf, &neigh->neighbor_main_addr, -1);
1009     abuf_appendf(abuf,
1010                "<td>%s</td>" "<td>%s</td>" "<td>%s</td>"
1011                "<td>%d</td>", (neigh->status == SYM) ? "YES" : "NO", neigh->is_mpr ? "YES" : "NO",
1012                olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
1013
1014     abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
1015
1016     for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
1017       struct ipaddr_str strbuf;
1018       abuf_appendf(abuf, "<option>%s</option>\n",
1019                  olsr_ip_to_string(&strbuf, &list_2->neighbor_2->neighbor_2_addr));
1020     }
1021     abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
1022   } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
1023
1024   abuf_puts(abuf, "</table>\n");
1025 }
1026
1027 static void
1028 build_topo_body(struct autobuf *abuf)
1029 {
1030   struct tc_entry *tc;
1031   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1032
1033   section_title(abuf, "Topology Entries");
1034   abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>",
1035              colspan, colspan);
1036   if (olsr_cnf->lq_level > 0) {
1037     abuf_puts(abuf, "<th>Linkcost</th>");
1038   }
1039   abuf_puts(abuf, "</tr>\n");
1040
1041   OLSR_FOR_ALL_TC_ENTRIES(tc) {
1042     struct tc_edge_entry *tc_edge;
1043     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
1044       if (tc_edge->edge_inv) {
1045         abuf_puts(abuf, "<tr>");
1046         build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1047         build_ipaddr_with_link(abuf, &tc->addr, -1);
1048         if (olsr_cnf->lq_level > 0) {
1049           struct lqtextbuffer lqbuffer1, lqbuffer2;
1050           abuf_appendf(abuf, "<td>(%s) %s</td>\n",
1051                      get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
1052         }
1053         abuf_puts(abuf, "</tr>\n");
1054       }
1055     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1056   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1057
1058   abuf_puts(abuf, "</table>\n");
1059 }
1060
1061 static void
1062 build_mid_body(struct autobuf *abuf)
1063 {
1064   int idx;
1065   const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1066
1067   section_title(abuf, "MID Entries");
1068   abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1069
1070   /* MID */
1071   for (idx = 0; idx < HASHSIZE; idx++) {
1072     struct mid_entry *entry;
1073     for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
1074       int mid_cnt;
1075       struct mid_address *alias;
1076       abuf_puts(abuf, "<tr>");
1077       build_ipaddr_with_link(abuf, &entry->main_addr, -1);
1078       abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1079
1080       for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
1081         struct ipaddr_str strbuf;
1082         abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
1083       }
1084       abuf_appendf(abuf, "</select> (%d)</td></tr>\n", mid_cnt);
1085     }
1086   }
1087
1088   abuf_puts(abuf, "</table>\n");
1089 }
1090
1091 static void
1092 build_nodes_body(struct autobuf *abuf)
1093 {
1094   build_neigh_body(abuf);
1095   build_topo_body(abuf);
1096   build_mid_body(abuf);
1097 }
1098
1099 static void
1100 build_all_body(struct autobuf *abuf)
1101 {
1102   build_config_body(abuf);
1103   build_routes_body(abuf);
1104   build_neigh_body(abuf);
1105   build_topo_body(abuf);
1106   build_mid_body(abuf);
1107 #ifdef __linux__
1108   build_sgw_body(abuf);
1109 #endif /* __linux__ */
1110 #ifdef HTTPINFO_PUD
1111   build_pud_body(abuf);
1112 #endif /* HTTPINFO_PUD */
1113 }
1114
1115 #ifdef HTTPINFO_PUD
1116 /**
1117  * Determine if a nmeaINFO structure has a certain field.
1118  * We need this function locally because nmealib might not be loaded.
1119  *
1120  * @param present the presence field
1121  * @param fieldName use a name from nmeaINFO_FIELD
1122  * @return a boolean, true when the structure has the requested field
1123  */
1124 static inline bool nmea_INFO_is_present_local(uint32_t present, nmeaINFO_FIELD fieldName) {
1125   return ((present & fieldName) != 0);
1126 }
1127
1128 static const char * NA_STRING = "N.A.";
1129 static const char * SAT_INUSE_COLOR = "lime";
1130 static const char * SAT_NOTINUSE_COLOR = "red";
1131
1132 static void build_pud_body(struct autobuf *abuf) {
1133         TransmitGpsInformation * txGpsInfo = olsr_cnf->pud_position;
1134         char * nodeId;
1135         char nodeIdString[256];
1136         bool datePresent;
1137         bool timePresent;
1138
1139         abuf_puts(abuf, "<h2>Position</h2>");
1140
1141         if (!txGpsInfo) {
1142                 abuf_puts(abuf, "<p><b>" PUD_PLUGIN_ABBR " plugin not loaded</b></p>\n");
1143                 return;
1144         }
1145
1146         nodeId = (char *) txGpsInfo->nodeId;
1147
1148         if (!nodeId || !strlen(nodeId)) {
1149                 inet_ntop(olsr_cnf->ip_version, &olsr_cnf->main_addr, &nodeIdString[0], sizeof(nodeIdString));
1150                 nodeId = nodeIdString;
1151         }
1152
1153         /* start of table */
1154         abuf_puts(abuf,
1155                 "<p><table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
1156                 "<tr><th>Parameter</th><th>&nbsp;&nbsp;</th><th>Unit</th><th>&nbsp;&nbsp;</th><th>Value</th></tr>\n"
1157         );
1158
1159         /* nodeId */
1160         abuf_appendf(abuf,
1161                 "<tr><td>Name</td><td></td><td></td><td></td><td id=\"nodeId\">%s</td></tr>\n",
1162                 nodeId
1163         );
1164
1165         /* utc */
1166         abuf_puts(abuf, "<tr><td>Date / Time</td><td></td><td>UTC</td><td></td><td id=\"utc\">");
1167         datePresent = nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
1168         timePresent = nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME);
1169         if (datePresent || timePresent) {
1170                 if (datePresent) {
1171                         abuf_appendf(abuf, "%04d%02d%02d",
1172                                 txGpsInfo->txPosition.nmeaInfo.utc.year + 1900,
1173                                 txGpsInfo->txPosition.nmeaInfo.utc.mon + 1,
1174                                 txGpsInfo->txPosition.nmeaInfo.utc.day);
1175                 }
1176                 if (datePresent && timePresent) {
1177                         abuf_puts(abuf, " ");
1178                 }
1179                 if (timePresent) {
1180                         abuf_appendf(abuf, "%02d:%02d:%02d.%02d",
1181                                 txGpsInfo->txPosition.nmeaInfo.utc.hour,
1182                                 txGpsInfo->txPosition.nmeaInfo.utc.min,
1183                                 txGpsInfo->txPosition.nmeaInfo.utc.sec,
1184                                 txGpsInfo->txPosition.nmeaInfo.utc.hsec);
1185                 }
1186         } else {
1187                 abuf_puts(abuf, NA_STRING);
1188         }
1189         abuf_puts(abuf, "</td></tr>\n");
1190
1191         /* present */
1192         abuf_puts(abuf, "<tr><td>Input Fields</td><td></td><td></td><td></td><td id=\"present\">");
1193         if (txGpsInfo->txPosition.nmeaInfo.present != 0) {
1194     const int id[] = {
1195         SMASK,
1196         UTCDATE,
1197         UTCTIME,
1198         SIG,
1199         FIX,
1200         PDOP,
1201         HDOP,
1202         VDOP,
1203         LAT,
1204         LON,
1205         ELV,
1206         SPEED,
1207         TRACK,
1208         MTRACK,
1209         MAGVAR,
1210         SATINUSECOUNT,
1211         SATINUSE,
1212         SATINVIEW,
1213         0 };
1214                 const char * ids[] = {
1215         "SMASK",
1216         "UTCDATE",
1217         "UTCTIME",
1218         "SIG",
1219         "FIX",
1220         "PDOP",
1221         "HDOP",
1222         "VDOP",
1223         "LAT",
1224         "LON",
1225         "ELV",
1226         "SPEED",
1227         "TRACK",
1228         "MTRACK",
1229         "MAGVAR",
1230         "SATINUSECOUNT",
1231         "SATINUSE",
1232         "SATINVIEW" };
1233                 bool printed = false;
1234                 int i = 0;
1235                 int count = 0;
1236
1237                 while (id[i] != 0) {
1238                         if (txGpsInfo->txPosition.nmeaInfo.present & id[i]) {
1239                                 if (printed) {
1240                                   if (count >= 8) {
1241                                     abuf_puts(abuf, "<br/>");
1242                                     count = 0;
1243                                   } else {
1244                                     abuf_puts(abuf, "&nbsp;");
1245                                   }
1246                                 }
1247                                 abuf_puts(abuf, ids[i]);
1248                                 count++;
1249                                 printed = true;
1250                         }
1251                         i++;
1252                 }
1253         } else {
1254                 abuf_puts(abuf, NA_STRING);
1255         }
1256         abuf_puts(abuf, "</td></tr>\n");
1257
1258         /* smask */
1259         abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
1260         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SMASK)
1261                         && (txGpsInfo->txPosition.nmeaInfo.smask != GPNON)) {
1262                 const int id[] = { GPGGA, GPGSA, GPGSV, GPRMC, GPVTG, GPNON };
1263                 const char * ids[] = { "GPGGA", "GPGSA", "GPGSV", "GPRMC", "GPVTG" };
1264                 bool printed = false;
1265                 int i = 0;
1266
1267                 while (id[i] != GPNON) {
1268                         if (txGpsInfo->txPosition.nmeaInfo.smask & id[i]) {
1269                                 if (printed)
1270                                         abuf_puts(abuf, "&nbsp;");
1271                                 abuf_puts(abuf, ids[i]);
1272                                 printed = true;
1273                         }
1274                         i++;
1275                 }
1276         } else {
1277                 abuf_puts(abuf, NA_STRING);
1278         }
1279         abuf_puts(abuf, "</td></tr>\n");
1280
1281         /* sig */
1282         abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
1283         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
1284                 const char * s;
1285                 switch (txGpsInfo->txPosition.nmeaInfo.sig) {
1286                         case NMEA_SIG_BAD:
1287                                 s = "Invalid";
1288                                 break;
1289                         case NMEA_SIG_LOW:
1290                                 s = "Fix";
1291                                 break;
1292                         case NMEA_SIG_MID:
1293                                 s = "Differential";
1294                                 break;
1295                         case NMEA_SIG_HIGH:
1296                                 s = "Sensitive";
1297                                 break;
1298                         case NMEA_SIG_RTKIN:
1299                                 s = "Real Time Kinematic";
1300                                 break;
1301                         case NMEA_SIG_FLRTK:
1302                                 s = "Float RTK";
1303                                 break;
1304                         case NMEA_SIG_ESTIM:
1305                                 s = "Estimated (Dead Reckoning)";
1306                                 break;
1307                         case NMEA_SIG_MAN:
1308                                 s = "Manual Input Mode";
1309                                 break;
1310                         case NMEA_SIG_SIM:
1311                                 s = "Simulation Mode";
1312                                 break;
1313                         default:
1314                                 s = "Unknown";
1315                                 break;
1316                 }
1317                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.sig);
1318         } else {
1319                 abuf_puts(abuf, NA_STRING);
1320         }
1321         abuf_puts(abuf, "</td></tr>\n");
1322
1323         /* fix */
1324         abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
1325         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
1326                 const char * s;
1327                 switch (txGpsInfo->txPosition.nmeaInfo.fix) {
1328                         case NMEA_FIX_BAD:
1329                                 s = "BAD";
1330                                 break;
1331                         case NMEA_FIX_2D:
1332                                 s = "2D";
1333                                 break;
1334                         case NMEA_FIX_3D:
1335                                 s = "3D";
1336                                 break;
1337                         default:
1338                                 s = "Unknown";
1339                                 break;
1340                 }
1341                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.fix);
1342         } else {
1343                 abuf_puts(abuf, NA_STRING);
1344         }
1345         abuf_puts(abuf, "</td></tr>\n");
1346
1347         /* PDOP */
1348         abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
1349         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
1350                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.PDOP);
1351         } else {
1352                 abuf_puts(abuf, NA_STRING);
1353         }
1354         abuf_puts(abuf, "</td></tr>\n");
1355
1356         /* HDOP */
1357         abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
1358         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
1359                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.HDOP);
1360         } else {
1361                 abuf_puts(abuf, NA_STRING);
1362         }
1363         abuf_puts(abuf, "</td></tr>\n");
1364
1365         /* VDOP */
1366         abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
1367         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
1368                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.VDOP);
1369         } else {
1370                 abuf_puts(abuf, NA_STRING);
1371         }
1372         abuf_puts(abuf, "</td></tr>\n");
1373
1374         /* lat */
1375         abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
1376         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
1377                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lat);
1378         } else {
1379                 abuf_puts(abuf, NA_STRING);
1380         }
1381         abuf_puts(abuf, "</td></tr>\n");
1382
1383         /* lon */
1384         abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
1385         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1386                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lon);
1387         } else {
1388                 abuf_puts(abuf, NA_STRING);
1389         }
1390         abuf_puts(abuf, "</td></tr>\n");
1391
1392         /* elv */
1393         abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
1394         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
1395                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elv);
1396         } else {
1397                 abuf_puts(abuf, NA_STRING);
1398         }
1399         abuf_puts(abuf, "</td></tr>\n");
1400
1401         /* speed */
1402         abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
1403         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
1404                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.speed);
1405         } else {
1406                 abuf_puts(abuf, NA_STRING);
1407         }
1408         abuf_puts(abuf, "</td></tr>\n");
1409
1410         /* track */
1411         abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
1412         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
1413                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.track);
1414         } else {
1415                 abuf_puts(abuf, NA_STRING);
1416         }
1417         abuf_puts(abuf, "</td></tr>\n");
1418
1419         /* mtrack */
1420         abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
1421         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
1422                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.mtrack);
1423         } else {
1424                 abuf_puts(abuf, NA_STRING);
1425         }
1426         abuf_puts(abuf, "</td></tr>\n");
1427
1428         /* magvar */
1429         abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
1430         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
1431                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.magvar);
1432         } else {
1433                 abuf_puts(abuf, NA_STRING);
1434         }
1435         abuf_puts(abuf, "</td></tr>\n");
1436
1437         /* end of table */
1438         abuf_puts(abuf, "</table></p>\n");
1439
1440         /* sats */
1441         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
1442                 int cnt = 0;
1443
1444                 abuf_puts(abuf, "<p>\n");
1445                 abuf_puts(abuf, "Satellite Infomation:\n");
1446                 abuf_puts(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"satinfo\">\n");
1447                 abuf_puts(abuf, "<tbody align=\"center\">\n");
1448                 abuf_puts(abuf,
1449                                 "<tr><th>ID</th><th>In Use</th><th>Elevation (degrees)</th><th>Azimuth (degrees)</th><th>Signal (dB)</th></tr>\n");
1450
1451                 if (txGpsInfo->txPosition.nmeaInfo.satinfo.inview) {
1452                         int satIndex;
1453                         for (satIndex = 0; satIndex < NMEA_MAXSAT; satIndex++) {
1454                                 nmeaSATELLITE * sat = &txGpsInfo->txPosition.nmeaInfo.satinfo.sat[satIndex];
1455                                 if (sat->id) {
1456                                         bool inuse = false;
1457                                         const char * inuseStr;
1458
1459                                         if (!nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
1460                                                 inuseStr = NA_STRING;
1461                                         } else {
1462                                                 int inuseIndex;
1463                                                 for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
1464                                                         if (txGpsInfo->txPosition.nmeaInfo.satinfo.in_use[inuseIndex] == sat->id) {
1465                                                                 inuse = true;
1466                                                                 break;
1467                                                         }
1468                                                 }
1469                                                 if (inuse) {
1470                                                         inuseStr = "yes";
1471                                                 } else {
1472                                                         inuseStr = "no";
1473                                                 }
1474                                         }
1475
1476                                         abuf_appendf(abuf, "<tr><td>%02d</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03d</td><td>%02d</td></tr>\n",
1477                                                         sat->id, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elv, sat->azimuth, sat->sig);
1478                                         cnt++;
1479                                 }
1480                         }
1481                 }
1482
1483                 if (!cnt) {
1484                         abuf_puts(abuf, "<tr><td colspan=\"5\">none</td></tr>\n");
1485                 }
1486
1487                 abuf_puts(abuf, "</tbody></table>\n");
1488                 abuf_puts(abuf, "</p>\n");
1489         }
1490
1491         /* add Google Maps and OpenStreetMap links when we have both lat and lon */
1492         if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)
1493                         && nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1494                 const char * c = nodeId;
1495
1496                 abuf_appendf(abuf,
1497                         "<p>\n"
1498                         "<a href=\"http://maps.google.com/maps?q=%f,+%f+%%28",
1499                         txGpsInfo->txPosition.nmeaInfo.lat,
1500                         txGpsInfo->txPosition.nmeaInfo.lon
1501                 );
1502
1503                 while (*c != '\0') {
1504                         if (*c == ' ' || *c == '\t') {
1505                                 abuf_puts(abuf, "+");
1506                         } else {
1507                                 abuf_appendf(abuf, "%c", *c);
1508                         }
1509                         c++;
1510                 }
1511
1512                 abuf_puts(abuf, "%29&amp;iwloc=A\">Show on Google Maps</a></p>\n");
1513
1514                 abuf_appendf(abuf,
1515                         "<p>\n"
1516                         "<a href=\"http://www.openstreetmap.org/index.html?mlat=%f&amp;mlon=%f&amp;zoom=15&amp;layers=M\">Show on OpenStreetMap</a></p>\n",
1517                         txGpsInfo->txPosition.nmeaInfo.lat,
1518                         txGpsInfo->txPosition.nmeaInfo.lon
1519                 );
1520         }
1521 }
1522 #endif /* HTTPINFO_PUD */
1523
1524 #ifdef __linux__
1525
1526 /**
1527  * Construct the sgw table for a given ip version
1528  *
1529  * @param abuf the string buffer
1530  * @param ipv6 true for IPv6, false for IPv4
1531  */
1532 static void sgw_ipvx(struct autobuf *abuf, bool ipv6) {
1533   struct gateway_entry * current_gw;
1534   struct gw_list * list;
1535   struct gw_container_entry * gw;
1536
1537   list = ipv6 ? &gw_list_ipv6 : &gw_list_ipv4;
1538   if (!list->count) {
1539     abuf_appendf(abuf, "<p><b>No IPv%s Gateways</b></p>\n", ipv6 ? "6" : "4");
1540   } else {
1541     char buf[INET6_ADDRSTRLEN];
1542     memset(buf, 0, sizeof(buf));
1543
1544     abuf_appendf(abuf, "<p><b>IPv%s Gateways</b></p>\n", ipv6 ? "6" : "4");
1545     abuf_puts(abuf, "<p>\n");
1546     abuf_appendf(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"sgw_ipv%s\">\n", ipv6 ? "6" : "4");
1547     abuf_puts(abuf, "  <tbody align=\"center\">\n");
1548     abuf_puts(abuf, "    <tr>\n");
1549     abuf_puts(abuf, "      <th><center>Originator</center></th>\n");
1550     abuf_puts(abuf, "      <th><center>Prefix</center></th>\n");
1551     abuf_puts(abuf, "      <th><center>Uplink (kbps)</center></th>\n");
1552     abuf_puts(abuf, "      <th><center>Downlink (kbps)</center></th>\n");
1553     abuf_puts(abuf, "      <th><center>Path Cost</center></th>\n");
1554     abuf_puts(abuf, "      <th><center>IPv4</center></th>\n");
1555     abuf_puts(abuf, "      <th><center>IPv4 NAT</center></th>\n");
1556     abuf_puts(abuf, "      <th><center>IPv6</center></th>\n");
1557     abuf_puts(abuf, "      <th><center>Tunnel Name</center></th>\n");
1558     abuf_puts(abuf, "      <th><center>Destination</center></th>\n");
1559     abuf_puts(abuf, "      <th><center>Cost</center></th>\n");
1560     abuf_puts(abuf, "    </tr>\n");
1561
1562     current_gw = olsr_get_inet_gateway(false);
1563     OLSR_FOR_ALL_GWS(&list->head, gw) {
1564       if (gw) {
1565         struct gwtextbuffer gwbuf;
1566         bool is_current = (current_gw && (gw->gw == current_gw));
1567
1568         if (is_current) {
1569           abuf_puts(abuf, "    <tr bgcolor=\"lime\">\n");
1570         } else {
1571           abuf_puts(abuf, "    <tr>\n");
1572         }
1573
1574         if (!gw->gw) {
1575           int i;
1576           for (i = 0; i < 8; i++) {
1577             abuf_puts(abuf, "      <td></td>\n");
1578           }
1579         } else {
1580           struct tc_entry* tc = olsr_lookup_tc_entry(&gw->gw->originator);
1581           olsr_linkcost etx = ROUTE_COST_BROKEN;
1582           struct lqtextbuffer lcbuf;
1583           if (tc) {
1584             etx = tc->path_cost;
1585           }
1586
1587           abuf_appendf(abuf, "      <td>%s</td>\n", inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->gw->originator, buf, sizeof(buf)));
1588           abuf_appendf(abuf, "      <td>%s</td>\n", olsr_ip_prefix_to_string(&gw->gw->external_prefix));
1589           abuf_appendf(abuf, "      <td>%u</td>\n", gw->gw->uplink);
1590           abuf_appendf(abuf, "      <td>%u</td>\n", gw->gw->downlink);
1591           abuf_appendf(abuf, "      <td>%s</td>\n", get_linkcost_text(etx, true, &lcbuf));
1592           abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv4 ? "yes" : "no");
1593           abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv4nat ? "yes" : "no");
1594           abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv6 ? "yes" : "no");
1595         }
1596         if (!gw->tunnel) {
1597           int i;
1598           for (i = 0; i < 2; i++) {
1599             abuf_puts(abuf, "      <td></td>\n");
1600           }
1601         } else {
1602           abuf_appendf(abuf, "      <td>%s</td>\n", gw->tunnel->if_name);
1603           abuf_appendf(abuf, "      <td>%s</td>\n", inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->tunnel->target, buf, sizeof(buf)));
1604         }
1605         abuf_appendf(abuf, "      <td>%s</td>\n", get_gwcost_text(!gw->gw ? INT64_MAX : gw->gw->path_cost, &gwbuf));
1606         abuf_puts(abuf, "    </tr>\n");
1607       }
1608     } OLSR_FOR_ALL_GWS_END(gw);
1609     abuf_puts(abuf, "  </tbody>\n");
1610     abuf_puts(abuf, "</table>\n");
1611     abuf_puts(abuf, "</p>\n");
1612   }
1613 }
1614
1615 static void build_sgw_body(struct autobuf *abuf) {
1616   abuf_puts(abuf, "<h2>Smart Gateway System</h2>\n");
1617
1618   if (!olsr_cnf->smart_gw_active) {
1619     abuf_puts(abuf, "<p><b>Smart Gateway system is not enabled</b></p>\n");
1620     return;
1621   }
1622
1623   sgw_ipvx(abuf, false);
1624   sgw_ipvx(abuf, true);
1625 }
1626 #endif /* __linux__ */
1627
1628 static void
1629 build_about_body(struct autobuf *abuf)
1630 {
1631   abuf_appendf(abuf,
1632                   "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
1633                   "Compiled "
1634 #ifdef ADMIN_INTERFACE
1635                   "<em>with experimental admin interface</em> "
1636 #endif /* ADMIN_INTERFACE */
1637                   "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
1638                   "the client with various dynamic web pages representing\n"
1639                   "the current olsrd status.<br/>The different pages include:\n"
1640                   "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1641                   "about the current olsrd configuration. This includes various\n"
1642                   "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1643                   "etc. Information about the current status of the interfaces on\n"
1644                   "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1645                   "plugins are shown with their plugin parameters. Finally all local\n"
1646                   "HNA entries are shown. These are the networks that the local host\n"
1647                   "will anounce itself as a gateway to.</li>\n"
1648                   "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1649                   "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n" "or HNA).</li>\n"
1650                   "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1651                   "links, neighbors, topology, MID and HNA entries.</li>\n"
1652                   "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1653                   "This is to make all information available as easy as possible(for example\n"
1654                   "for a script) and using as few resources as possible.</li>\n"
1655 #ifdef ADMIN_INTERFACE
1656                   "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1657                   "As of now it is not working at all but it provides a impression of\n"
1658                   "the future possibilities of httpinfo. This is to be a interface to\n"
1659                   "changing olsrd settings in realtime. These settings include various\n"
1660                   "\"basic\" settings and local HNA settings.</li>\n"
1661 #endif /* ADMIN_INTERFACE */
1662                   "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
1663                   "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1664                   "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1665                   "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date,
1666                   build_host);
1667 }
1668
1669 static void
1670 build_cfgfile_body(struct autobuf *abuf)
1671 {
1672   abuf_puts(abuf,
1673              "\n\n" "<strong>This is a automatically generated configuration\n"
1674              "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
1675   olsrd_write_cnf_autobuf(abuf, olsr_cnf);
1676
1677   abuf_puts(abuf, "</pre>\n<hr/>\n");
1678 }
1679
1680 static int
1681 check_allowed_ip(const struct allowed_net *const my_allowed_nets, const union olsr_ip_addr *const addr)
1682 {
1683   const struct allowed_net *alln;
1684   for (alln = my_allowed_nets; alln != NULL; alln = alln->next) {
1685     if (ip_in_net(addr, &alln->prefix)) {
1686       return 1;
1687     }
1688   }
1689   return 0;
1690 }
1691
1692 /*
1693  * Local Variables:
1694  * c-basic-offset: 2
1695  * indent-tabs-mode: nil
1696  * End:
1697  */