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