build: get rid of HTTPINFO_PUD define
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
index 7be19f3..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"
-#ifdef HTTPINFO_PUD
-  #include <pud/src/pud.h>
-  #include <nmea/sentence.h>
-#endif
+#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
 
@@ -182,9 +187,11 @@ static void build_nodes_body(struct autobuf *);
 
 static void build_all_body(struct autobuf *);
 
-#ifdef HTTPINFO_PUD
+#ifdef __linux__
+static void build_sgw_body(struct autobuf *);
+#endif /* __linux__ */
+
 static void build_pud_body(struct autobuf *);
-#endif
 
 static void build_about_body(struct autobuf *);
 
@@ -212,25 +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 HTTPINFO_PUD
+#ifdef __linux__
+  {"Smart Gateway", "sgw", build_sgw_body, true},
+#endif /* __linux__ */
   {"Position", "position", build_pud_body, true},
-#endif
   {"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}
@@ -256,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)
@@ -318,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 */
@@ -343,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");
@@ -359,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;
@@ -369,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",
@@ -403,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
@@ -427,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++;
@@ -483,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"
@@ -504,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++;
@@ -544,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
@@ -628,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");
@@ -740,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
+#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);
@@ -903,7 +908,7 @@ build_config_body(struct autobuf *abuf)
   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");
@@ -1098,89 +1103,33 @@ build_all_body(struct autobuf *abuf)
   build_neigh_body(abuf);
   build_topo_body(abuf);
   build_mid_body(abuf);
-#ifdef HTTPINFO_PUD
+#ifdef __linux__
+  build_sgw_body(abuf);
+#endif /* __linux__ */
   build_pud_body(abuf);
-#endif
 }
-
-#ifdef HTTPINFO_PUD
 /**
- * Determine whether a given nmeaINFO structure has a certain field.
- * Note: this is duplicated from nmealib to avoid depending on that library
+ * Determine if a nmeaINFO structure has a certain field.
+ * We need this function locally because nmealib might not be loaded.
  *
- * nmeaINFO dependencies:
- <pre>
- field/sentence GPGGA   GPGSA   GPGSV   GPRMC   GPVTG
- smask:         x       x       x       x       x
- utc:           x                       x
- sig:           x                       x
- fix:                   x               x
- PDOP:                  x
- HDOP:          x       x
- VDOP:                  x
- lat:           x                       x
- lon:           x                       x
- elv:           x
- speed:                                 x       x
- direction:                             x       x
- declination:                                   x
- satinfo:               x       x
- </pre>
- *
- * @param smask
- * the smask of a nmeaINFO structure
- * @param fieldName
- * the field name
- *
- * @return
- * - true when the nmeaINFO structure has the field
- * - false otherwise
+ * @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 bool nmea_INFO_has_field_local(int smask, nmeaINFO_FIELD fieldName) {
-       switch (fieldName) {
-               case SMASK:
-                       return true;
-
-               case UTC:
-               case SIG:
-               case LAT:
-               case LON:
-                       return ((smask & (GPGGA | GPRMC)) != 0);
-
-               case FIX:
-                       return ((smask & (GPGSA | GPRMC)) != 0);
-
-               case PDOP:
-               case VDOP:
-                       return ((smask & GPGSA) != 0);
-
-               case HDOP:
-                       return ((smask & (GPGGA | GPGSA)) != 0);
-
-               case ELV:
-                       return ((smask & GPGGA) != 0);
-
-               case SPEED:
-               case DIRECTION:
-                       return ((smask & (GPRMC | GPVTG)) != 0);
-
-               case DECLINATION:
-                       return ((smask & GPVTG) != 0);
-
-               case SATINFO:
-                       return ((smask & (GPGSA | GPGSV)) != 0);
-
-               default:
-                       return false;
-       }
+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>");
 
@@ -1210,16 +1159,92 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* utc */
        abuf_puts(abuf, "<tr><td>Date / Time</td><td></td><td>UTC</td><td></td><td id=\"utc\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, UTC)) {
-               abuf_appendf(abuf, "%04d%02d%02d %02d:%02d:%02d.%02d",
-                       txGpsInfo->txPosition.nmeaInfo.utc.year + 1900,
-                       txGpsInfo->txPosition.nmeaInfo.utc.mon,
-                       txGpsInfo->txPosition.nmeaInfo.utc.day,
-                       txGpsInfo->txPosition.nmeaInfo.utc.hour,
-                       txGpsInfo->txPosition.nmeaInfo.utc.min,
-                       txGpsInfo->txPosition.nmeaInfo.utc.sec,
-                       txGpsInfo->txPosition.nmeaInfo.utc.hsec
-               );
+       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);
        }
@@ -1227,7 +1252,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* smask */
        abuf_puts(abuf, "<tr><td>Input Sentences</td><td></td><td></td><td></td><td id=\"smask\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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" };
@@ -1250,7 +1275,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* sig */
        abuf_puts(abuf, "<tr><td>Signal Strength</td><td></td><td></td><td></td><td id=\"sig\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, SIG)) {
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
                const char * s;
                switch (txGpsInfo->txPosition.nmeaInfo.sig) {
                        case NMEA_SIG_BAD:
@@ -1265,6 +1290,21 @@ static void build_pud_body(struct autobuf *abuf) {
                        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;
@@ -1277,7 +1317,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* fix */
        abuf_puts(abuf, "<tr><td>Fix</td><td></td><td></td><td></td><td id=\"fix\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, FIX)) {
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
                const char * s;
                switch (txGpsInfo->txPosition.nmeaInfo.fix) {
                        case NMEA_FIX_BAD:
@@ -1301,7 +1341,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* PDOP */
        abuf_puts(abuf, "<tr><td>PDOP</td><td></td><td></td><td></td><td id=\"pdop\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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);
@@ -1310,7 +1350,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* HDOP */
        abuf_puts(abuf, "<tr><td>HDOP</td><td></td><td></td><td></td><td id=\"hdop\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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);
@@ -1319,7 +1359,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* VDOP */
        abuf_puts(abuf, "<tr><td>VDOP</td><td></td><td></td><td></td><td id=\"vdop\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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);
@@ -1328,7 +1368,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* lat */
        abuf_puts(abuf, "<tr><td>Latitude</td><td></td><td>degrees</td><td></td><td id=\"lat\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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);
@@ -1337,7 +1377,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* lon */
        abuf_puts(abuf, "<tr><td>Longitude</td><td></td><td>degrees</td><td></td><td id=\"lon\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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);
@@ -1346,7 +1386,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* elv */
        abuf_puts(abuf, "<tr><td>Elevation</td><td></td><td>m</td><td></td><td id=\"elv\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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);
@@ -1355,39 +1395,97 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* speed */
        abuf_puts(abuf, "<tr><td>Speed</td><td></td><td>kph</td><td></td><td id=\"speed\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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");
 
-       /* direction */
-       abuf_puts(abuf, "<tr><td>Direction</td><td></td><td>degrees</td><td></td><td id=\"direction\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, DIRECTION)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.direction);
+       /* 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");
 
-       /* declination */
-       abuf_puts(abuf, "<tr><td>Declination</td><td></td><td>degrees</td><td></td><td id=\"declination\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, DECLINATION)) {
-               abuf_appendf(abuf, "%f", txGpsInfo->txPosition.nmeaInfo.declination);
+       /* 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");
 
-       // FIXME add satinfo
+       /* 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_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, LAT)
-                       && nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.smask, 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,
@@ -1416,17 +1514,118 @@ static void build_pud_body(struct autobuf *abuf) {
                );
        }
 }
-#endif
+
+#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"
@@ -1451,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"
@@ -1468,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