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