build: get rid of HTTPINFO_PUD define
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
index d6ea831..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
 #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/receiver.h>
-  #include <pud/src/pud.h>
-  #include <nmea/info.h>
-  #include <nmea/sentence.h>
-#endif /* HTTPINFO_PUD */
+#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"
@@ -93,9 +99,6 @@
 #define OS "Undefined"
 #endif /* OS */
 
-static char copyright_string[] __attribute__ ((unused)) =
-  "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
-
 #define MAX_CLIENTS 3
 
 #define MAX_HTTPREQ_SIZE (1024 * 10)
@@ -184,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 /* HTTPINFO_PUD */
 
 static void build_about_body(struct autobuf *);
 
@@ -218,9 +223,10 @@ 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 /* HTTPINFO_PUD */
   {"All", "all", build_all_body, true},
 #ifdef ADMIN_INTERFACE
   {"Admin", "admin", build_admin_body, true},
@@ -312,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 */
@@ -397,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
@@ -498,7 +503,7 @@ 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
@@ -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");
@@ -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,12 +1103,11 @@ 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 /* HTTPINFO_PUD */
 }
-
-#ifdef HTTPINFO_PUD
 /**
  * Determine if a nmeaINFO structure has a certain field.
  * We need this function locally because nmealib might not be loaded.
@@ -1112,8 +1116,8 @@ build_all_body(struct autobuf *abuf)
  * @param fieldName use a name from nmeaINFO_FIELD
  * @return a boolean, true when the structure has the requested field
  */
-static inline bool nmea_INFO_has_field_local(uint32_t present, nmeaINFO_FIELD fieldName) {
-       return ((present & fieldName) != 0);
+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.";
@@ -1155,13 +1159,13 @@ 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\">");
-       datePresent = nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCDATE);
-       timePresent = nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, UTCTIME);
+       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,
+                               txGpsInfo->txPosition.nmeaInfo.utc.mon + 1,
                                txGpsInfo->txPosition.nmeaInfo.utc.day);
                }
                if (datePresent && timePresent) {
@@ -1179,9 +1183,76 @@ static void build_pud_body(struct autobuf *abuf) {
        }
        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_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, 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" };
@@ -1204,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.present, SIG)) {
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SIG)) {
                const char * s;
                switch (txGpsInfo->txPosition.nmeaInfo.sig) {
                        case NMEA_SIG_BAD:
@@ -1246,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.present, FIX)) {
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, FIX)) {
                const char * s;
                switch (txGpsInfo->txPosition.nmeaInfo.fix) {
                        case NMEA_FIX_BAD:
@@ -1270,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.present, 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);
@@ -1279,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.present, 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);
@@ -1288,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.present, 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);
@@ -1297,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.present, 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);
@@ -1306,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.present, 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);
@@ -1315,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.present, 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);
@@ -1324,7 +1395,7 @@ 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.present, 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);
@@ -1333,7 +1404,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* track */
        abuf_puts(abuf, "<tr><td>Track</td><td></td><td>degrees</td><td></td><td id=\"track\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, 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);
@@ -1342,7 +1413,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* mtrack */
        abuf_puts(abuf, "<tr><td>Magnetic Track</td><td></td><td>degrees</td><td></td><td id=\"mtrack\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, 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);
@@ -1351,7 +1422,7 @@ static void build_pud_body(struct autobuf *abuf) {
 
        /* magvar */
        abuf_puts(abuf, "<tr><td>Magnetic Variation</td><td></td><td>degrees</td><td></td><td id=\"magvar\">");
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, 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);
@@ -1362,7 +1433,7 @@ static void build_pud_body(struct autobuf *abuf) {
        abuf_puts(abuf, "</table></p>\n");
 
        /* sats */
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
+       if (nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SATINVIEW)) {
                int cnt = 0;
 
                abuf_puts(abuf, "<p>\n");
@@ -1380,7 +1451,7 @@ static void build_pud_body(struct autobuf *abuf) {
                                        bool inuse = false;
                                        const char * inuseStr;
 
-                                       if (!nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
+                                       if (!nmea_INFO_is_present_local(txGpsInfo->txPosition.nmeaInfo.present, SATINUSE)) {
                                                inuseStr = NA_STRING;
                                        } else {
                                                int inuseIndex;
@@ -1413,8 +1484,8 @@ static void build_pud_body(struct autobuf *abuf) {
        }
 
        /* add Google Maps and OpenStreetMap links when we have both lat and lon */
-       if (nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, LAT)
-                       && nmea_INFO_has_field_local(txGpsInfo->txPosition.nmeaInfo.present, 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,
@@ -1443,13 +1514,114 @@ static void build_pud_body(struct autobuf *abuf) {
                );
        }
 }
-#endif /* HTTPINFO_PUD */
+
+#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> "