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