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