build: get rid of HTTPINFO_PUD define
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
index 9965ed6..3c329c1 100644 (file)
@@ -1,7 +1,11 @@
-
 /*
- * HTTP Info plugin for the olsr.org OLSR daemon
- * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
+ * The olsr.org Optimized Link-State Routing daemon (olsrd)
+ *
+ * (c) by the OLSR project
+ *
+ * See our Git repository to find out who worked on this file
+ * and thus is a copyright holder on it.
+ *
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
-#ifdef WIN32
+#ifdef _WIN32
 #include <io.h>
-#else
+#else /* _WIN32 */
 #include <netdb.h>
-#endif
+#endif /* _WIN32 */
 
 #include "olsr.h"
+#include "builddata.h"
 #include "olsr_cfg.h"
 #include "interfaces.h"
+#include "gateway.h"
+#include "gateway_costs.h"
 #include "olsr_protocol.h"
 #include "net_olsr.h"
 #include "link_set.h"
 #include "ipcalc.h"
+#include "defs.h"
 #include "lq_plugin.h"
 #include "common/autobuf.h"
+#include <pud/src/receiver.h>
+#include <pud/src/pud.h>
+#include <nmea/info.h>
+#include <nmea/sentence.h>
 
 #include "olsrd_httpinfo.h"
 #include "admin_interface.h"
 
 #ifdef OS
 #undef OS
-#endif
+#endif /* OS */
 
-#ifdef WIN32
+#ifdef _WIN32
 #define close(x) closesocket(x)
 #define OS "Windows"
-#endif
-#ifdef linux
+#endif /* _WIN32 */
+#ifdef __linux__
 #define OS "GNU/Linux"
-#endif
+#endif /* __linux__ */
 #if defined __FreeBSD__ || defined __FreeBSD_kernel__
 #define OS "FreeBSD"
-#endif
+#endif /* defined __FreeBSD__ || defined __FreeBSD_kernel__ */
 
 #ifndef OS
 #define OS "Undefined"
-#endif
-
-static char copyright_string[] __attribute__ ((unused)) =
-  "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
+#endif /* OS */
 
 #define MAX_CLIENTS 3
 
@@ -178,6 +187,12 @@ static void build_nodes_body(struct autobuf *);
 
 static void build_all_body(struct autobuf *);
 
+#ifdef __linux__
+static void build_sgw_body(struct autobuf *);
+#endif /* __linux__ */
+
+static void build_pud_body(struct autobuf *);
+
 static void build_about_body(struct autobuf *);
 
 static void build_cfgfile_body(struct autobuf *);
@@ -204,22 +219,18 @@ static int outbuffer_count;
 
 static struct timer_entry *writetimer_entry;
 
-#if 0
-int netsprintf(char *str, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
-static int netsprintf_direct = 0;
-static int netsprintf_error = 0;
-#define sprintf netsprintf
-#define NETDIRECT
-#endif
-
 static const struct tab_entry tab_entries[] = {
   {"Configuration", "config", build_config_body, true},
   {"Routes", "routes", build_routes_body, true},
   {"Links/Topology", "nodes", build_nodes_body, true},
+#ifdef __linux__
+  {"Smart Gateway", "sgw", build_sgw_body, true},
+#endif /* __linux__ */
+  {"Position", "position", build_pud_body, true},
   {"All", "all", build_all_body, true},
 #ifdef ADMIN_INTERFACE
   {"Admin", "admin", build_admin_body, true},
-#endif
+#endif /* ADMIN_INTERFACE */
   {"About", "about", build_about_body, true},
   {"FOO", "cfgfile", build_cfgfile_body, false},
   {NULL, NULL, NULL, false}
@@ -245,7 +256,7 @@ static const struct dynamic_file_entry dynamic_files[] = {
   {"set_values", process_set_values},
   {NULL, NULL}
 };
-#endif
+#endif /* ADMIN_INTERFACE */
 
 static int
 get_http_socket(int port)
@@ -307,8 +318,7 @@ olsrd_plugin_init(void)
   http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
 
   if (http_socket < 0) {
-    fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
-    exit(0);
+    olsr_exit("HTTPINFO: could not initialize HTTP socket", EXIT_FAILURE);
   }
 
   /* Register socket */
@@ -332,9 +342,9 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
   size_t header_length = 0;
   size_t c = 0;
   int r = 1;
-#ifdef linux
+#ifdef __linux__
   struct timeval timeout = { 0, 200 };
-#endif
+#endif /* __linux__ */
 
   if (outbuffer_count >= MAX_CLIENTS) {
     olsr_printf(1, "(HTTPINFO) maximum number of connection reached\n");
@@ -348,7 +358,7 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
     goto close_connection;
   }
 
-#ifdef linux
+#ifdef __linux__
   if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
     olsr_printf(1, "(HTTPINFO)SO_RCVTIMEO failed %s\n", strerror(errno));
     goto close_connection;
@@ -358,7 +368,7 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
     olsr_printf(1, "(HTTPINFO)SO_SNDTIMEO failed %s\n", strerror(errno));
     goto close_connection;
   }
-#endif
+#endif /* __linux__ */
   if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
     struct ipaddr_str strbuf;
     olsr_printf(0, "HTTP request from non-allowed host %s!\n",
@@ -392,7 +402,7 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
   }
 
   olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
-  abuf_init(&body_abuf, 102400);
+  abuf_init(&body_abuf, AUTOBUFCHUNK);
 
   if (!strcmp(req_type, "POST")) {
 #ifdef ADMIN_INTERFACE
@@ -416,7 +426,7 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
       }
       i++;
     }
-#endif
+#endif /* ADMIN_INTERFACE */
     /* We only support GET */
     abuf_puts(&body_abuf, HTTP_400_MSG);
     stats.ill_hits++;
@@ -472,7 +482,7 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
       }
       netsprintf_error = 0;
       netsprintf_direct = 1;
-#endif
+#endif /* NETDIRECT */
       abuf_appendf(&body_abuf,
                  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<head>\n"
                  "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
@@ -493,16 +503,16 @@ parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int fla
       stats.ok_hits++;
 
       abuf_appendf(&body_abuf,
-                 "</table>\n" "<div id=\"footer\">\n" "<center>\n" "(C)2005 Andreas T&oslash;nnesen<br/>\n"
+                 "</table>\n" "<div id=\"footer\">\n" "<center><br/>\n"
                  "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
 
 #ifdef NETDIRECT
       netsprintf_direct = 1;
       goto close_connection;
-#else
+#else /* NETDIRECT */
       header_length = build_http_header(HTTP_OK, true, body_abuf.len, header_buf, sizeof(header_buf));
       goto send_http_data;
-#endif
+#endif /* NETDIRECT */
     }
 
     stats.ill_hits++;
@@ -533,11 +543,17 @@ send_http_data:
     }
   }
   abuf_free(&body_abuf);
+  /*
+   * client_socket is stored in outbuffer_socket[outbuffer_count] and closed
+   * by the httpinfo_write_data timer callback, so don't close it here
+   */
   return;
 
 close_connection:
   abuf_free(&body_abuf);
-  close(client_socket);
+  if (client_socket >= 0) {
+    close(client_socket);
+  }
 }
 
 static void
@@ -617,7 +633,7 @@ build_http_header(http_header_type type, bool is_html, uint32_t msgsize, char *b
   size += strftime(&buf[size], bufsize - size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
 
   /* Server version */
-  size += snprintf(&buf[size], bufsize - size, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
+  size += snprintf(&buf[size], bufsize - size, "Server: %s %s\r\n", PLUGIN_NAME, HTTP_VERSION);
 
   /* connection-type */
   size += snprintf(&buf[size], bufsize - size, "Connection: closed\r\n");
@@ -729,10 +745,10 @@ build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_i
 {
   struct ipaddr_str ipaddrstr;
   const struct hostent *const hp =
-#ifndef WIN32
-    resolve_ip_addresses ? gethostbyaddr(ipaddr, olsr_cnf->ipsize,
+#ifndef _WIN32
+    resolve_ip_addresses ? gethostbyaddr((const void *)ipaddr, olsr_cnf->ipsize,
                                          olsr_cnf->ip_version) :
-#endif
+#endif /* _WIN32 */
     NULL;
   /* Print the link only if there is no prefix_len and ip_version is AF_INET */
   const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen) && (olsr_cnf->ip_version == AF_INET);
@@ -854,10 +870,10 @@ build_config_body(struct autobuf *abuf)
 
   abuf_puts(abuf, "</tr>\n<tr>\n");
 
-  abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", olsr_cnf->pollrate);
+  abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", (double)olsr_cnf->pollrate);
   abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
   abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
-  abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
+  abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", (double)olsr_cnf->lq_nat_thresh);
 
   abuf_puts(abuf, "</tr>\n<tr>\n");
 
@@ -875,9 +891,9 @@ build_config_body(struct autobuf *abuf)
     abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
                olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
     if (olsr_cnf->use_hysteresis) {
-      abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
-      abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", olsr_cnf->hysteresis_param.thr_low,
-                 olsr_cnf->hysteresis_param.thr_high);
+      abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", (double)olsr_cnf->hysteresis_param.scaling);
+      abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", (double)olsr_cnf->hysteresis_param.thr_low,
+                 (double)olsr_cnf->hysteresis_param.thr_high);
     }
   }
 
@@ -885,14 +901,14 @@ build_config_body(struct autobuf *abuf)
              olsr_cnf->lq_level ? "Enabled" : "Disabled");
   if (olsr_cnf->lq_level) {
     abuf_appendf(abuf, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
-               olsr_cnf->lq_aging);
+               (double)olsr_cnf->lq_aging);
   }
   abuf_puts(abuf, "</tr></table>\n");
 
   abuf_puts(abuf, "<h2>Interfaces</h2>\n");
   abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
   for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
-    const struct interface *const rifs = ifs->interf;
+    const struct interface_olsr *const rifs = ifs->interf;
     abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
     if (!rifs) {
       abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
@@ -967,7 +983,7 @@ build_neigh_body(struct autobuf *abuf)
     abuf_puts(abuf, "<tr>");
     build_ipaddr_with_link(abuf, &the_link->local_iface_addr, -1);
     build_ipaddr_with_link(abuf, &the_link->neighbor_iface_addr, -1);
-    abuf_appendf(abuf, "<td>%0.2f</td>", the_link->L_link_quality);
+    abuf_appendf(abuf, "<td>%0.2f</td>", (double)the_link->L_link_quality);
     if (olsr_cnf->lq_level > 0) {
       struct lqtextbuffer lqbuffer1, lqbuffer2;
       abuf_appendf(abuf, "<td>(%s) %s</td>", get_link_entry_text(the_link, '/', &lqbuffer1),
@@ -1087,17 +1103,529 @@ build_all_body(struct autobuf *abuf)
   build_neigh_body(abuf);
   build_topo_body(abuf);
   build_mid_body(abuf);
+#ifdef __linux__
+  build_sgw_body(abuf);
+#endif /* __linux__ */
+  build_pud_body(abuf);
 }
+/**
+ * Determine if a nmeaINFO structure has a certain field.
+ * We need this function locally because nmealib might not be loaded.
+ *
+ * @param present the presence field
+ * @param fieldName use a name from nmeaINFO_FIELD
+ * @return a boolean, true when the structure has the requested field
+ */
+static INLINE bool nmea_INFO_is_present_local(uint32_t present, nmeaINFO_FIELD fieldName) {
+  return ((present & fieldName) != 0);
+}
+
+static const char * NA_STRING = "N.A.";
+static const char * SAT_INUSE_COLOR = "lime";
+static const char * SAT_NOTINUSE_COLOR = "red";
+
+static void build_pud_body(struct autobuf *abuf) {
+       TransmitGpsInformation * txGpsInfo = olsr_cnf->pud_position;
+       char * nodeId;
+       char nodeIdString[256];
+       bool datePresent;
+       bool timePresent;
+
+       abuf_puts(abuf, "<h2>Position</h2>");
+
+       if (!txGpsInfo) {
+               abuf_puts(abuf, "<p><b>" PUD_PLUGIN_ABBR " plugin not loaded</b></p>\n");
+               return;
+       }
+
+       nodeId = (char *) txGpsInfo->nodeId;
+
+       if (!nodeId || !strlen(nodeId)) {
+               inet_ntop(olsr_cnf->ip_version, &olsr_cnf->main_addr, &nodeIdString[0], sizeof(nodeIdString));
+               nodeId = nodeIdString;
+       }
+
+       /* start of table */
+       abuf_puts(abuf,
+               "<p><table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
+               "<tr><th>Parameter</th><th>&nbsp;&nbsp;</th><th>Unit</th><th>&nbsp;&nbsp;</th><th>Value</th></tr>\n"
+       );
+
+       /* nodeId */
+       abuf_appendf(abuf,
+               "<tr><td>Name</td><td></td><td></td><td></td><td id=\"nodeId\">%s</td></tr>\n",
+               nodeId
+       );
+
+       /* utc */
+       abuf_puts(abuf, "<tr><td>Date / Time</td><td></td><td>UTC</td><td></td><td id=\"utc\">");
+       datePresent = nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
+       timePresent = nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME);
+       if (datePresent || timePresent) {
+               if (datePresent) {
+                       abuf_appendf(abuf, "%04d%02d%02d",
+                               txGpsInfo->txPosition.nmeaInfo.utc.year + 1900,
+                               txGpsInfo->txPosition.nmeaInfo.utc.mon + 1,
+                               txGpsInfo->txPosition.nmeaInfo.utc.day);
+               }
+               if (datePresent && timePresent) {
+                       abuf_puts(abuf, " ");
+               }
+               if (timePresent) {
+                       abuf_appendf(abuf, "%02d:%02d:%02d.%02d",
+                               txGpsInfo->txPosition.nmeaInfo.utc.hour,
+                               txGpsInfo->txPosition.nmeaInfo.utc.min,
+                               txGpsInfo->txPosition.nmeaInfo.utc.sec,
+                               txGpsInfo->txPosition.nmeaInfo.utc.hsec);
+               }
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* present */
+       abuf_puts(abuf, "<tr><td>Input Fields</td><td></td><td></td><td></td><td id=\"present\">");
+       if (txGpsInfo->txPosition.nmeaInfo.present != 0) {
+    const int id[] = {
+        SMASK,
+        UTCDATE,
+        UTCTIME,
+        SIG,
+        FIX,
+        PDOP,
+        HDOP,
+        VDOP,
+        LAT,
+        LON,
+        ELV,
+        SPEED,
+        TRACK,
+        MTRACK,
+        MAGVAR,
+        SATINUSECOUNT,
+        SATINUSE,
+        SATINVIEW,
+        0 };
+               const char * ids[] = {
+        "SMASK",
+        "UTCDATE",
+        "UTCTIME",
+        "SIG",
+        "FIX",
+        "PDOP",
+        "HDOP",
+        "VDOP",
+        "LAT",
+        "LON",
+        "ELV",
+        "SPEED",
+        "TRACK",
+        "MTRACK",
+        "MAGVAR",
+        "SATINUSECOUNT",
+        "SATINUSE",
+        "SATINVIEW" };
+               bool printed = false;
+               int i = 0;
+               int count = 0;
+
+               while (id[i] != 0) {
+                       if (txGpsInfo->txPosition.nmeaInfo.present & id[i]) {
+                               if (printed) {
+                                 if (count >= 8) {
+                                   abuf_puts(abuf, "<br/>");
+                                   count = 0;
+                                 } else {
+                                   abuf_puts(abuf, "&nbsp;");
+                                 }
+                               }
+                               abuf_puts(abuf, ids[i]);
+                               count++;
+                               printed = true;
+                       }
+                       i++;
+               }
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* smask */
+       abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SMASK)
+                       && (txGpsInfo->txPosition.nmeaInfo.smask != GPNON)) {
+               const int id[] = { GPGGA, GPGSA, GPGSV, GPRMC, GPVTG, GPNON };
+               const char * ids[] = { "GPGGA", "GPGSA", "GPGSV", "GPRMC", "GPVTG" };
+               bool printed = false;
+               int i = 0;
+
+               while (id[i] != GPNON) {
+                       if (txGpsInfo->txPosition.nmeaInfo.smask & id[i]) {
+                               if (printed)
+                                       abuf_puts(abuf, "&nbsp;");
+                               abuf_puts(abuf, ids[i]);
+                               printed = true;
+                       }
+                       i++;
+               }
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* sig */
+       abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
+               const char * s;
+               switch (txGpsInfo->txPosition.nmeaInfo.sig) {
+                       case NMEA_SIG_BAD:
+                               s = "Invalid";
+                               break;
+                       case NMEA_SIG_LOW:
+                               s = "Fix";
+                               break;
+                       case NMEA_SIG_MID:
+                               s = "Differential";
+                               break;
+                       case NMEA_SIG_HIGH:
+                               s = "Sensitive";
+                               break;
+                       case NMEA_SIG_RTKIN:
+                               s = "Real Time Kinematic";
+                               break;
+                       case NMEA_SIG_FLRTK:
+                               s = "Float RTK";
+                               break;
+                       case NMEA_SIG_ESTIM:
+                               s = "Estimated (Dead Reckoning)";
+                               break;
+                       case NMEA_SIG_MAN:
+                               s = "Manual Input Mode";
+                               break;
+                       case NMEA_SIG_SIM:
+                               s = "Simulation Mode";
+                               break;
+                       default:
+                               s = "Unknown";
+                               break;
+               }
+               abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.sig);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* fix */
+       abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
+               const char * s;
+               switch (txGpsInfo->txPosition.nmeaInfo.fix) {
+                       case NMEA_FIX_BAD:
+                               s = "BAD";
+                               break;
+                       case NMEA_FIX_2D:
+                               s = "2D";
+                               break;
+                       case NMEA_FIX_3D:
+                               s = "3D";
+                               break;
+                       default:
+                               s = "Unknown";
+                               break;
+               }
+               abuf_appendf(abuf, "%s (%d)", s, txGpsInfo->txPosition.nmeaInfo.fix);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* PDOP */
+       abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, PDOP)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.PDOP);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* HDOP */
+       abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, HDOP)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.HDOP);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* VDOP */
+       abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, VDOP)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.VDOP);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* lat */
+       abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lat);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* lon */
+       abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.lon);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* elv */
+       abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, ELV)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.elv);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* speed */
+       abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SPEED)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.speed);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* track */
+       abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, TRACK)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.track);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* mtrack */
+       abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, MTRACK)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.mtrack);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* magvar */
+       abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, MAGVAR)) {
+               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.magvar);
+       } else {
+               abuf_puts(abuf, NA_STRING);
+       }
+       abuf_puts(abuf, "</td></tr>\n");
+
+       /* end of table */
+       abuf_puts(abuf, "</table></p>\n");
+
+       /* sats */
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
+               int cnt = 0;
+
+               abuf_puts(abuf, "<p>\n");
+               abuf_puts(abuf, "Satellite Infomation:\n");
+               abuf_puts(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"satinfo\">\n");
+               abuf_puts(abuf, "<tbody align=\"center\">\n");
+               abuf_puts(abuf,
+                               "<tr><th>ID</th><th>In Use</th><th>Elevation (degrees)</th><th>Azimuth (degrees)</th><th>Signal (dB)</th></tr>\n");
+
+               if (txGpsInfo->txPosition.nmeaInfo.satinfo.inview) {
+                       int satIndex;
+                       for (satIndex = 0; satIndex < NMEA_MAXSAT; satIndex++) {
+                               nmeaSATELLITE * sat = &txGpsInfo->txPosition.nmeaInfo.satinfo.sat[satIndex];
+                               if (sat->id) {
+                                       bool inuse = false;
+                                       const char * inuseStr;
+
+                                       if (!nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
+                                               inuseStr = NA_STRING;
+                                       } else {
+                                               int inuseIndex;
+                                               for (inuseIndex = 0; inuseIndex < NMEA_MAXSAT; inuseIndex++) {
+                                                       if (txGpsInfo->txPosition.nmeaInfo.satinfo.in_use[inuseIndex] == sat->id) {
+                                                               inuse = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if (inuse) {
+                                                       inuseStr = "yes";
+                                               } else {
+                                                       inuseStr = "no";
+                                               }
+                                       }
+
+                                       abuf_appendf(abuf, "<tr><td>%02d</td><td bgcolor=\"%s\">%s</td><td>%02d</td><td>%03d</td><td>%02d</td></tr>\n",
+                                                       sat->id, inuse ? SAT_INUSE_COLOR : SAT_NOTINUSE_COLOR, inuseStr, sat->elv, sat->azimuth, sat->sig);
+                                       cnt++;
+                               }
+                       }
+               }
+
+               if (!cnt) {
+                       abuf_puts(abuf, "<tr><td colspan=\"5\">none</td></tr>\n");
+               }
+
+               abuf_puts(abuf, "</tbody></table>\n");
+               abuf_puts(abuf, "</p>\n");
+       }
+
+       /* add Google Maps and OpenStreetMap links when we have both lat and lon */
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)
+                       && nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, LON)) {
+               const char * c = nodeId;
+
+               abuf_appendf(abuf,
+                       "<p>\n"
+                       "<a href=\"http://maps.google.com/maps?q=%f,+%f+%%28",
+                       txGpsInfo->txPosition.nmeaInfo.lat,
+                       txGpsInfo->txPosition.nmeaInfo.lon
+               );
+
+               while (*c != '\0') {
+                       if (*c == ' ' || *c == '\t') {
+                               abuf_puts(abuf, "+");
+                       } else {
+                               abuf_appendf(abuf, "%c", *c);
+                       }
+                       c++;
+               }
+
+               abuf_puts(abuf, "%29&amp;iwloc=A\">Show on Google Maps</a></p>\n");
+
+               abuf_appendf(abuf,
+                       "<p>\n"
+                       "<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",
+                       txGpsInfo->txPosition.nmeaInfo.lat,
+                       txGpsInfo->txPosition.nmeaInfo.lon
+               );
+       }
+}
+
+#ifdef __linux__
+
+/**
+ * Construct the sgw table for a given ip version
+ *
+ * @param abuf the string buffer
+ * @param ipv6 true for IPv6, false for IPv4
+ */
+static void sgw_ipvx(struct autobuf *abuf, bool ipv6) {
+  struct gateway_entry * current_gw;
+  struct gw_list * list;
+  struct gw_container_entry * gw;
+
+  list = ipv6 ? &gw_list_ipv6 : &gw_list_ipv4;
+  if (!list->count) {
+    abuf_appendf(abuf, "<p><b>No IPv%s Gateways</b></p>\n", ipv6 ? "6" : "4");
+  } else {
+    char buf[INET6_ADDRSTRLEN];
+    memset(buf, 0, sizeof(buf));
+
+    abuf_appendf(abuf, "<p><b>IPv%s Gateways</b></p>\n", ipv6 ? "6" : "4");
+    abuf_puts(abuf, "<p>\n");
+    abuf_appendf(abuf, "<table border=\"1\" cellpadding=\"2\" cellspacing=\"0\" id=\"sgw_ipv%s\">\n", ipv6 ? "6" : "4");
+    abuf_puts(abuf, "  <tbody align=\"center\">\n");
+    abuf_puts(abuf, "    <tr>\n");
+    abuf_puts(abuf, "      <th><center>Originator</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Prefix</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Uplink (kbps)</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Downlink (kbps)</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Path Cost</center></th>\n");
+    abuf_puts(abuf, "      <th><center>IPv4</center></th>\n");
+    abuf_puts(abuf, "      <th><center>IPv4 NAT</center></th>\n");
+    abuf_puts(abuf, "      <th><center>IPv6</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Tunnel Name</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Destination</center></th>\n");
+    abuf_puts(abuf, "      <th><center>Cost</center></th>\n");
+    abuf_puts(abuf, "    </tr>\n");
+
+    current_gw = olsr_get_inet_gateway(false);
+    OLSR_FOR_ALL_GWS(&list->head, gw) {
+      struct gwtextbuffer gwbuf;
+      bool is_current = (current_gw && (gw->gw == current_gw));
+
+      if (is_current) {
+        abuf_puts(abuf, "    <tr bgcolor=\"lime\">\n");
+      } else {
+        abuf_puts(abuf, "    <tr>\n");
+      }
+
+      if (!gw->gw) {
+        int i;
+        for (i = 0; i < 8; i++) {
+          abuf_puts(abuf, "      <td></td>\n");
+        }
+      } else {
+        struct tc_entry* tc = olsr_lookup_tc_entry(&gw->gw->originator);
+        olsr_linkcost etx = ROUTE_COST_BROKEN;
+        struct lqtextbuffer lcbuf;
+        if (tc) {
+          etx = tc->path_cost;
+        }
+
+        abuf_appendf(abuf, "      <td>%s</td>\n", inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->gw->originator, buf, sizeof(buf)));
+        abuf_appendf(abuf, "      <td>%s</td>\n", olsr_ip_prefix_to_string(&gw->gw->external_prefix));
+        abuf_appendf(abuf, "      <td>%u</td>\n", gw->gw->uplink);
+        abuf_appendf(abuf, "      <td>%u</td>\n", gw->gw->downlink);
+        abuf_appendf(abuf, "      <td>%s</td>\n", get_linkcost_text(etx, true, &lcbuf));
+        abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv4 ? "yes" : "no");
+        abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv4nat ? "yes" : "no");
+        abuf_appendf(abuf, "      <td>%s</td>\n", gw->gw->ipv6 ? "yes" : "no");
+      }
+      if (!gw->tunnel) {
+        int i;
+        for (i = 0; i < 2; i++) {
+          abuf_puts(abuf, "      <td></td>\n");
+        }
+      } else {
+        abuf_appendf(abuf, "      <td>%s</td>\n", gw->tunnel->if_name);
+        abuf_appendf(abuf, "      <td>%s</td>\n", inet_ntop(ipv6 ? AF_INET6 : AF_INET, &gw->tunnel->target, buf, sizeof(buf)));
+      }
+      abuf_appendf(abuf, "      <td>%s</td>\n", get_gwcost_text(!gw->gw ? INT64_MAX : gw->gw->path_cost, &gwbuf));
+      abuf_puts(abuf, "    </tr>\n");
+    } OLSR_FOR_ALL_GWS_END(gw);
+    abuf_puts(abuf, "  </tbody>\n");
+    abuf_puts(abuf, "</table>\n");
+    abuf_puts(abuf, "</p>\n");
+  }
+}
+
+static void build_sgw_body(struct autobuf *abuf) {
+  abuf_puts(abuf, "<h2>Smart Gateway System</h2>\n");
+
+  if (!olsr_cnf->smart_gw_active) {
+    abuf_puts(abuf, "<p><b>Smart Gateway system is not enabled</b></p>\n");
+    return;
+  }
+
+  sgw_ipvx(abuf, false);
+  sgw_ipvx(abuf, true);
+}
+#endif /* __linux__ */
 
 static void
 build_about_body(struct autobuf *abuf)
 {
   abuf_appendf(abuf,
-                  "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas T&oslash;nnesen (C)2005.<br/>\n"
+                  "<strong>" PLUGIN_NAME "</strong><br/><br/>\n"
                   "Compiled "
 #ifdef ADMIN_INTERFACE
                   "<em>with experimental admin interface</em> "
-#endif
+#endif /* ADMIN_INTERFACE */
                   "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
                   "the client with various dynamic web pages representing\n"
                   "the current olsrd status.<br/>The different pages include:\n"
@@ -1122,7 +1650,7 @@ build_about_body(struct autobuf *abuf)
                   "the future possibilities of httpinfo. This is to be a interface to\n"
                   "changing olsrd settings in realtime. These settings include various\n"
                   "\"basic\" settings and local HNA settings.</li>\n"
-#endif
+#endif /* ADMIN_INTERFACE */
                   "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
                   "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
                   "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
@@ -1139,10 +1667,6 @@ build_cfgfile_body(struct autobuf *abuf)
   olsrd_write_cnf_autobuf(abuf, olsr_cnf);
 
   abuf_puts(abuf, "</pre>\n<hr/>\n");
-
-#if 0
-  printf("RETURNING %d\n", size);
-#endif
 }
 
 static int