httpinfo: add smart gateway information tab
[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_has_field_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_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
1171         timePresent = nmea_INFO_has_field_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         /* smask */
1195         abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
1196         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SMASK)
1197                         && (txGpsInfo->txPosition.nmeaInfo.smask != GPNON)) {
1198                 const int id[] = { GPGGA, GPGSA, GPGSV, GPRMC, GPVTG, GPNON };
1199                 const char * ids[] = { "GPGGA", "GPGSA", "GPGSV", "GPRMC", "GPVTG" };
1200                 bool printed = false;
1201                 int i = 0;
1202
1203                 while (id[i] != GPNON) {
1204                         if (txGpsInfo->txPosition.nmeaInfo.smask & id[i]) {
1205                                 if (printed)
1206                                         abuf_puts(abuf, "&nbsp;");
1207                                 abuf_puts(abuf, ids[i]);
1208                                 printed = true;
1209                         }
1210                         i++;
1211                 }
1212         } else {
1213                 abuf_puts(abuf, NA_STRING);
1214         }
1215         abuf_puts(abuf, "</td></tr>\n");
1216
1217         /* sig */
1218         abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
1219         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
1220                 const char * s;
1221                 switch (txGpsInfo->txPosition.nmeaInfo.sig) {
1222                         case NMEA_SIG_BAD:
1223                                 s = "Invalid";
1224                                 break;
1225                         case NMEA_SIG_LOW:
1226                                 s = "Fix";
1227                                 break;
1228                         case NMEA_SIG_MID:
1229                                 s = "Differential";
1230                                 break;
1231                         case NMEA_SIG_HIGH:
1232                                 s = "Sensitive";
1233                                 break;
1234                         case NMEA_SIG_RTKIN:
1235                                 s = "Real Time Kinematic";
1236                                 break;
1237                         case NMEA_SIG_FLRTK:
1238                                 s = "Float RTK";
1239                                 break;
1240                         case NMEA_SIG_ESTIM:
1241                                 s = "Estimated (Dead Reckoning)";
1242                                 break;
1243                         case NMEA_SIG_MAN:
1244                                 s = "Manual Input Mode";
1245                                 break;
1246                         case NMEA_SIG_SIM:
1247                                 s = "Simulation Mode";
1248                                 break;
1249                         default:
1250                                 s = "Unknown";
1251                                 break;
1252                 }
1253                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.sig);
1254         } else {
1255                 abuf_puts(abuf, NA_STRING);
1256         }
1257         abuf_puts(abuf, "</td></tr>\n");
1258
1259         /* fix */
1260         abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
1261         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
1262                 const char * s;
1263                 switch (txGpsInfo->txPosition.nmeaInfo.fix) {
1264                         case NMEA_FIX_BAD:
1265                                 s = "BAD";
1266                                 break;
1267                         case NMEA_FIX_2D:
1268                                 s = "2D";
1269                                 break;
1270                         case NMEA_FIX_3D:
1271                                 s = "3D";
1272                                 break;
1273                         default:
1274                                 s = "Unknown";
1275                                 break;
1276                 }
1277                 abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.fix);
1278         } else {
1279                 abuf_puts(abuf, NA_STRING);
1280         }
1281         abuf_puts(abuf, "</td></tr>\n");
1282
1283         /* PDOP */
1284         abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
1285         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
1286                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.PDOP);
1287         } else {
1288                 abuf_puts(abuf, NA_STRING);
1289         }
1290         abuf_puts(abuf, "</td></tr>\n");
1291
1292         /* HDOP */
1293         abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
1294         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
1295                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.HDOP);
1296         } else {
1297                 abuf_puts(abuf, NA_STRING);
1298         }
1299         abuf_puts(abuf, "</td></tr>\n");
1300
1301         /* VDOP */
1302         abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
1303         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
1304                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.VDOP);
1305         } else {
1306                 abuf_puts(abuf, NA_STRING);
1307         }
1308         abuf_puts(abuf, "</td></tr>\n");
1309
1310         /* lat */
1311         abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
1312         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
1313                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lat);
1314         } else {
1315                 abuf_puts(abuf, NA_STRING);
1316         }
1317         abuf_puts(abuf, "</td></tr>\n");
1318
1319         /* lon */
1320         abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
1321         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1322                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lon);
1323         } else {
1324                 abuf_puts(abuf, NA_STRING);
1325         }
1326         abuf_puts(abuf, "</td></tr>\n");
1327
1328         /* elv */
1329         abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
1330         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
1331                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elv);
1332         } else {
1333                 abuf_puts(abuf, NA_STRING);
1334         }
1335         abuf_puts(abuf, "</td></tr>\n");
1336
1337         /* speed */
1338         abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
1339         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
1340                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.speed);
1341         } else {
1342                 abuf_puts(abuf, NA_STRING);
1343         }
1344         abuf_puts(abuf, "</td></tr>\n");
1345
1346         /* track */
1347         abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
1348         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
1349                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.track);
1350         } else {
1351                 abuf_puts(abuf, NA_STRING);
1352         }
1353         abuf_puts(abuf, "</td></tr>\n");
1354
1355         /* mtrack */
1356         abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
1357         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
1358                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.mtrack);
1359         } else {
1360                 abuf_puts(abuf, NA_STRING);
1361         }
1362         abuf_puts(abuf, "</td></tr>\n");
1363
1364         /* magvar */
1365         abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
1366         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
1367                 abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.magvar);
1368         } else {
1369                 abuf_puts(abuf, NA_STRING);
1370         }
1371         abuf_puts(abuf, "</td></tr>\n");
1372
1373         /* end of table */
1374         abuf_puts(abuf, "</table></p>\n");
1375
1376         /* sats */
1377         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
1378                 int cnt = 0;
1379
1380                 abuf_puts(abuf, "<p>\n");
1381                 abuf_puts(abuf, "Satellite Infomation:\n");
1382                 abuf_puts(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"satinfo\">\n");
1383                 abuf_puts(abuf, "<tbody align=\"center\">\n");
1384                 abuf_puts(abuf,
1385                                 "<tr><th>ID</th><th>In Use</th><th>Elevation (degrees)</th><th>Azimuth (degrees)</th><th>Signal (dB)</th></tr>\n");
1386
1387                 if (txGpsInfo->txPosition.nmeaInfo.satinfo.inview) {
1388                         int satIndex;
1389                         for (satIndex = 0; satIndex < NMEA_MAXSAT; satIndex++) {
1390                                 nmeaSATELLITE * sat = &txGpsInfo->txPosition.nmeaInfo.satinfo.sat[satIndex];
1391                                 if (sat->id) {
1392                                         bool inuse = false;
1393                                         const char * inuseStr;
1394
1395                                         if (!nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
1396                                                 inuseStr = NA_STRING;
1397                                         } else {
1398                                                 int inuseIndex;
1399                                                 for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
1400                                                         if (txGpsInfo->txPosition.nmeaInfo.satinfo.in_use[inuseIndex] == sat->id) {
1401                                                                 inuse = true;
1402                                                                 break;
1403                                                         }
1404                                                 }
1405                                                 if (inuse) {
1406                                                         inuseStr = "yes";
1407                                                 } else {
1408                                                         inuseStr = "no";
1409                                                 }
1410                                         }
1411
1412                                         abuf_appendf(abuf, "<tr><td>%02d</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03d</td><td>%02d</td></tr>\n",
1413                                                         sat->id, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elv, sat->azimuth, sat->sig);
1414                                         cnt++;
1415                                 }
1416                         }
1417                 }
1418
1419                 if (!cnt) {
1420                         abuf_puts(abuf, "<tr><td colspan=\"5\">none</td></tr>\n");
1421                 }
1422
1423                 abuf_puts(abuf, "</tbody></table>\n");
1424                 abuf_puts(abuf, "</p>\n");
1425         }
1426
1427         /* add Google Maps and OpenStreetMap links when we have both lat and lon */
1428         if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)
1429                         && nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
1430                 const char * c = nodeId;
1431
1432                 abuf_appendf(abuf,
1433                         "<p>\n"
1434                         "<a href=\"http://maps.google.com/maps?q=%f,+%f+%%28",
1435                         txGpsInfo->txPosition.nmeaInfo.lat,
1436                         txGpsInfo->txPosition.nmeaInfo.lon
1437                 );
1438
1439                 while (*c != '\0') {
1440                         if (*c == ' ' || *c == '\t') {
1441                                 abuf_puts(abuf, "+");
1442                         } else {
1443                                 abuf_appendf(abuf, "%c", *c);
1444                         }
1445                         c++;
1446                 }
1447
1448                 abuf_puts(abuf, "%29&amp;iwloc=A\">Show on Google Maps</a></p>\n");
1449
1450                 abuf_appendf(abuf,
1451                         "<p>\n"
1452                         "<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",
1453                         txGpsInfo->txPosition.nmeaInfo.lat,
1454                         txGpsInfo->txPosition.nmeaInfo.lon
1455                 );
1456         }
1457 }
1458 #endif /* HTTPINFO_PUD */
1459
1460 #ifdef __linux__
1461
1462 /**
1463  * Construct the sgw table for a given ip version
1464  *
1465  * @param abuf the string buffer
1466  * @param ipv6 true for IPv6, false for IPv4
1467  */
1468 static void sgw_ipvx(struct autobuf *abuf, bool ipv6) {
1469   struct gateway_entry * current_gw;
1470   struct gw_list * list;
1471   struct gw_container_entry * gw;
1472
1473   list = ipv6 ? &gw_list_ipv6 : &gw_list_ipv4;
1474   if (!list->count) {
1475     abuf_appendf(abuf, "<p><b>No IPv%s Gateways</b></p>\n", ipv6 ? "6" : "4");
1476   } else {
1477     char buf[INET6_ADDRSTRLEN];
1478     memset(buf, 0, sizeof(buf));
1479
1480     abuf_appendf(abuf, "<p><b>IPv%s Gateways</b></p>\n", ipv6 ? "6" : "4");
1481     abuf_puts(abuf, "<p>\n");
1482     abuf_appendf(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"sgw_ipv%s\">\n", ipv6 ? "6" : "4");
1483     abuf_puts(abuf, "  <tbody align=\"center\">\n");
1484     abuf_puts(abuf, "    <tr>\n");
1485     abuf_puts(abuf, "      <th>Originator</th>\n");
1486     abuf_puts(abuf, "      <th>Prefix</th>\n");
1487     abuf_puts(abuf, "      <th>Uplink (kbps)</th>\n");
1488     abuf_puts(abuf, "      <th>Downlink (kbps)</th>\n");
1489     abuf_puts(abuf, "      <th>IPv4</th>\n");
1490     abuf_puts(abuf, "      <th>IPv4 NAT</th>\n");
1491     abuf_puts(abuf, "      <th>IPv6</th>\n");
1492     abuf_puts(abuf, "      <th>Tunnel Name</th>\n");
1493     abuf_puts(abuf, "      <th>Destination</th>\n");
1494     abuf_puts(abuf, "      <th>Cost</th>\n");
1495     abuf_puts(abuf, "    </tr>\n");
1496
1497     current_gw = olsr_get_inet_gateway(false);
1498     OLSR_FOR_ALL_GWS(&list->head, gw) {
1499       if (gw) {
1500         bool is_current = (current_gw && (gw->gw == current_gw));
1501
1502         if (is_current) {
1503           abuf_puts(abuf, "    <tr bgcolor=\"lime\">\n");
1504         } else {
1505           abuf_puts(abuf, "    <tr>\n");
1506         }
1507
1508         if (!gw->gw) {
1509           int i;
1510           for (i = 0; i < 7; i++) {
1511             abuf_puts(abuf, "      <td></td>\n");
1512           }
1513         } else {
1514           abuf_appendf(abuf, "      <td>%s</td>\n", inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->gw->originator, buf, sizeof(buf)));
1515           abuf_appendf(abuf, "      <td>%s</td>\n", olsr_ip_prefix_to_string(&gw->gw->external_prefix));
1516           abuf_appendf(abuf, "      <td>%u</td>\n", gw->gw->uplink);
1517           abuf_appendf(abuf, "      <td>%u</td>\n", gw->gw->downlink);
1518           abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv4 ? "yes" : "no");
1519           abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv4nat ? "yes" : "no");
1520           abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv6 ? "yes" : "no");
1521         }
1522         if (!gw->tunnel) {
1523           int i;
1524           for (i = 0; i < 2; i++) {
1525             abuf_puts(abuf, "      <td></td>\n");
1526           }
1527         } else {
1528           abuf_appendf(abuf, "      <td>%s</td>\n", gw->tunnel->if_name);
1529           abuf_appendf(abuf, "      <td>%s</td>\n", inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->tunnel->target, buf, sizeof(buf)));
1530         }
1531         if (!gw->gw) {
1532           abuf_puts(abuf, "      <td></td>\n");
1533         } else {
1534           abuf_appendf(abuf, "      <td>%llu</td>\n", (long long unsigned int)gw->path_cost);
1535         }
1536         abuf_puts(abuf, "    </tr>\n");
1537       }
1538     } OLSR_FOR_ALL_GWS_END(gw);
1539     abuf_puts(abuf, "  </tbody>\n");
1540     abuf_puts(abuf, "</table>\n");
1541     abuf_puts(abuf, "</p>\n");
1542   }
1543 }
1544
1545 static void build_sgw_body(struct autobuf *abuf) {
1546   abuf_puts(abuf, "<h2>Smart Gateway System</h2>\n");
1547
1548   if (!olsr_cnf->smart_gw_active) {
1549     abuf_puts(abuf, "<p><b>Smart Gateway system is not enabled</b></p>\n");
1550     return;
1551   }
1552
1553   sgw_ipvx(abuf, false);
1554   sgw_ipvx(abuf, true);
1555 }
1556 #endif /* __linux__ */
1557
1558 static void
1559 build_about_body(struct autobuf *abuf)
1560 {
1561   abuf_appendf(abuf,
1562                   "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
1563                   "Compiled "
1564 #ifdef ADMIN_INTERFACE
1565                   "<em>with experimental admin interface</em> "
1566 #endif /* ADMIN_INTERFACE */
1567                   "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
1568                   "the client with various dynamic web pages representing\n"
1569                   "the current olsrd status.<br/>The different pages include:\n"
1570                   "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1571                   "about the current olsrd configuration. This includes various\n"
1572                   "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1573                   "etc. Information about the current status of the interfaces on\n"
1574                   "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1575                   "plugins are shown with their plugin parameters. Finally all local\n"
1576                   "HNA entries are shown. These are the networks that the local host\n"
1577                   "will anounce itself as a gateway to.</li>\n"
1578                   "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1579                   "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n" "or HNA).</li>\n"
1580                   "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1581                   "links, neighbors, topology, MID and HNA entries.</li>\n"
1582                   "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1583                   "This is to make all information available as easy as possible(for example\n"
1584                   "for a script) and using as few resources as possible.</li>\n"
1585 #ifdef ADMIN_INTERFACE
1586                   "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1587                   "As of now it is not working at all but it provides a impression of\n"
1588                   "the future possibilities of httpinfo. This is to be a interface to\n"
1589                   "changing olsrd settings in realtime. These settings include various\n"
1590                   "\"basic\" settings and local HNA settings.</li>\n"
1591 #endif /* ADMIN_INTERFACE */
1592                   "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
1593                   "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1594                   "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1595                   "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date,
1596                   build_host);
1597 }
1598
1599 static void
1600 build_cfgfile_body(struct autobuf *abuf)
1601 {
1602   abuf_puts(abuf,
1603              "\n\n" "<strong>This is a automatically generated configuration\n"
1604              "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
1605   olsrd_write_cnf_autobuf(abuf, olsr_cnf);
1606
1607   abuf_puts(abuf, "</pre>\n<hr/>\n");
1608 }
1609
1610 static int
1611 check_allowed_ip(const struct allowed_net *const my_allowed_nets, const union olsr_ip_addr *const addr)
1612 {
1613   const struct allowed_net *alln;
1614   for (alln = my_allowed_nets; alln != NULL; alln = alln->next) {
1615     if (ip_in_net(addr, &alln->prefix)) {
1616       return 1;
1617     }
1618   }
1619   return 0;
1620 }
1621
1622 /*
1623  * Local Variables:
1624  * c-basic-offset: 2
1625  * indent-tabs-mode: nil
1626  * End:
1627  */