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