summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-olsr/luasrc
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2014-12-03 15:17:05 +0100
committerJo-Philipp Wich <jow@openwrt.org>2015-01-08 16:26:20 +0100
commit1bb4822dca6113f73e3bc89e2acf15935e6f8e92 (patch)
tree35e16f100466e4e00657199b38bb3d87d52bf73f /applications/luci-app-olsr/luasrc
parent9edd0e46c3f880727738ce8ca6ff1c8b85f99ef4 (diff)
Rework LuCI build system
* Rename subdirectories to their repective OpenWrt package names * Make each LuCI module its own standalone package * Deploy a shared luci.mk which is used by each module Makefile Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
Diffstat (limited to 'applications/luci-app-olsr/luasrc')
-rw-r--r--applications/luci-app-olsr/luasrc/controller/olsr.lua413
-rw-r--r--applications/luci-app-olsr/luasrc/controller/olsr4.lua47
-rw-r--r--applications/luci-app-olsr/luasrc/controller/olsr6.lua47
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd.lua420
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd6.lua401
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrddisplay.lua23
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna.lua56
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna6.lua36
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface.lua189
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface6.lua176
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua270
-rw-r--r--applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins6.lua270
-rw-r--r--applications/luci-app-olsr/luasrc/tools/olsr.lua42
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/common_js.htm35
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/error_olsr.htm17
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/hna.htm129
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/interfaces.htm57
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/legend.htm24
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/mid.htm58
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/neighbors.htm181
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/overview.htm220
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/routes.htm148
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/smartgw.htm158
-rw-r--r--applications/luci-app-olsr/luasrc/view/status-olsr/topology.htm68
24 files changed, 3485 insertions, 0 deletions
diff --git a/applications/luci-app-olsr/luasrc/controller/olsr.lua b/applications/luci-app-olsr/luasrc/controller/olsr.lua
new file mode 100644
index 000000000..4573f690b
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/controller/olsr.lua
@@ -0,0 +1,413 @@
+module("luci.controller.olsr", package.seeall)
+
+function index()
+ local ipv4,ipv6
+ if nixio.fs.access("/etc/config/olsrd") then
+ ipv4 = 1
+ end
+ if nixio.fs.access("/etc/config/olsrd6") then
+ ipv6 = 1
+ end
+ if not ipv4 and not ipv6 then
+ return
+ end
+
+ require("luci.model.uci")
+ local uci = luci.model.uci.cursor_state()
+
+ uci:foreach("olsrd", "olsrd", function(s)
+ if s.SmartGateway and s.SmartGateway == "yes" then has_smartgw = true end
+ end)
+
+ local page = node("admin", "status", "olsr")
+ page.target = template("status-olsr/overview")
+ page.title = _("OLSR")
+ page.subindex = true
+
+ local page = node("admin", "status", "olsr", "json")
+ page.target = call("action_json")
+ page.title = nil
+ page.leaf = true
+
+ local page = node("admin", "status", "olsr", "neighbors")
+ page.target = call("action_neigh")
+ page.title = _("Neighbours")
+ page.subindex = true
+ page.order = 5
+
+ local page = node("admin", "status", "olsr", "routes")
+ page.target = call("action_routes")
+ page.title = _("Routes")
+ page.order = 10
+
+ local page = node("admin", "status", "olsr", "topology")
+ page.target = call("action_topology")
+ page.title = _("Topology")
+ page.order = 20
+
+ local page = node("admin", "status", "olsr", "hna")
+ page.target = call("action_hna")
+ page.title = _("HNA")
+ page.order = 30
+
+ local page = node("admin", "status", "olsr", "mid")
+ page.target = call("action_mid")
+ page.title = _("MID")
+ page.order = 50
+
+ if has_smartgw then
+ local page = node("admin", "status", "olsr", "smartgw")
+ page.target = call("action_smartgw")
+ page.title = _("SmartGW")
+ page.order = 60
+ end
+
+ local page = node("admin", "status", "olsr", "interfaces")
+ page.target = call("action_interfaces")
+ page.title = _("Interfaces")
+ page.order = 70
+
+ odsp = entry(
+ {"admin", "services", "olsrd", "display"},
+ cbi("olsr/olsrddisplay"), _("Display")
+ )
+
+end
+
+function action_json()
+ local http = require "luci.http"
+ local utl = require "luci.util"
+ local uci = require "luci.model.uci".cursor_state()
+ local jsonreq4
+ local jsonreq6
+
+ jsonreq4 = utl.exec("echo /status | nc 127.0.0.1 9090")
+ jsonreq6 = utl.exec("echo /status | nc ::1 9090")
+ http.prepare_content("application/json")
+ if not jsonreq4 or jsonreq4 == "" then
+ jsonreq4 = "{}"
+ end
+ if not jsonreq6 or jsonreq6 == "" then
+ jsonreq6 = "{}"
+ end
+ http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
+end
+
+function action_neigh(json)
+ local data, has_v4, has_v6, error = fetch_jsoninfo('links')
+
+ if error then
+ return
+ end
+
+ local uci = require "luci.model.uci".cursor_state()
+ local resolve = uci:get("luci_olsr", "general", "resolve")
+ local ntm = require "luci.model.network".init()
+ local devices = ntm:get_wifidevs()
+ local sys = require "luci.sys"
+ local assoclist = {}
+ --local neightbl = require "neightbl"
+ local ipc = require "luci.ip"
+
+ luci.sys.net.routes(function(r)
+ if r.dest:prefix() == 0 then
+ defaultgw = r.gateway:string()
+ end
+ end)
+
+ local function compare(a,b)
+ if a.proto == b.proto then
+ return a.linkCost < b.linkCost
+ else
+ return a.proto < b.proto
+ end
+ end
+
+ for _, dev in ipairs(devices) do
+ for _, net in ipairs(dev:get_wifinets()) do
+ assoclist[#assoclist+1] = {}
+ assoclist[#assoclist]['ifname'] = net.iwdata.ifname
+ assoclist[#assoclist]['network'] = net.iwdata.network
+ assoclist[#assoclist]['device'] = net.iwdata.device
+ assoclist[#assoclist]['list'] = net.iwinfo.assoclist
+ end
+ end
+
+ for k, v in ipairs(data) do
+ local interface
+ local snr = 0
+ local signal = 0
+ local noise = 0
+ local arptable = sys.net.arptable()
+ local mac = ""
+ local rmac = ""
+ local lmac = ""
+ local ip
+ local neihgt = {}
+
+ if resolve == "1" then
+ hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
+ if hostname then
+ v.hostname = hostname
+ end
+ end
+ if v.proto == '4' then
+ uci:foreach("network", "interface",function(vif)
+ if vif.ipaddr and vif.ipaddr == v.localIP then
+ interface = vif['.name'] or vif.interface
+ lmac = string.lower(vif.macaddr or "")
+ return
+ end
+ end)
+ for _, arpt in ipairs(arptable) do
+ ip = arpt['IP address']
+ if ip == v.remoteIP then
+ rmac = string.lower(arpt['HW address'] or "")
+ end
+ end
+ elseif v.proto == '6' then
+ uci:foreach("network", "interface",function(vif)
+ local name = vif['.name']
+ local net = ntm:get_network(name)
+ local device = net and net:get_interface()
+ local locip = ipc.IPv6(v.localIP)
+ if device and device:ip6addrs() and locip then
+ for _, a in ipairs(device:ip6addrs()) do
+ if not a:is6linklocal() then
+ if a:host() == locip:host() then
+ interface = name
+ --neihgt = neightbl.get(device.ifname) or {}
+ end
+ end
+ end
+ end
+ end)
+ --[[
+ for ip,mac in pairs(neihgt) do
+ if ip == v.remoteIP then
+ rmac = mac
+ end
+ end
+ ]]--
+ end
+ for _, val in ipairs(assoclist) do
+ if val.network == interface and val.list then
+ for assocmac, assot in pairs(val.list) do
+ assocmac = string.lower(assocmac or "")
+ if rmac == assocmac then
+ signal = tonumber(assot.signal)
+ noise = tonumber(assot.noise)
+ snr = (noise*-1) - (signal*-1)
+ end
+ end
+ end
+ end
+ if interface then
+ v.interface = interface
+ end
+ v.snr = snr
+ v.signal = signal
+ v.noise = noise
+ if rmac then
+ v.remoteMAC = rmac
+ end
+ if lmac then
+ v.localMAC = lmac
+ end
+
+ if defaultgw == v.remoteIP then
+ v.defaultgw = 1
+ end
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/neighbors", {links=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+function action_routes()
+ local data, has_v4, has_v6, error = fetch_jsoninfo('routes')
+ if error then
+ return
+ end
+
+ local uci = require "luci.model.uci".cursor_state()
+ local resolve = uci:get("luci_olsr", "general", "resolve")
+
+ for k, v in ipairs(data) do
+ if resolve == "1" then
+ local hostname = nixio.getnameinfo(v.gateway, nil, 100)
+ if hostname then
+ v.hostname = hostname
+ end
+ end
+ end
+
+ local function compare(a,b)
+ if a.proto == b.proto then
+ return a.rtpMetricCost < b.rtpMetricCost
+ else
+ return a.proto < b.proto
+ end
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/routes", {routes=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+function action_topology()
+ local data, has_v4, has_v6, error = fetch_jsoninfo('topology')
+ if error then
+ return
+ end
+
+ local function compare(a,b)
+ if a.proto == b.proto then
+ return a.tcEdgeCost < b.tcEdgeCost
+ else
+ return a.proto < b.proto
+ end
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/topology", {routes=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+function action_hna()
+ local data, has_v4, has_v6, error = fetch_jsoninfo('hna')
+ if error then
+ return
+ end
+
+ local uci = require "luci.model.uci".cursor_state()
+ local resolve = uci:get("luci_olsr", "general", "resolve")
+
+ local function compare(a,b)
+ if a.proto == b.proto then
+ return a.genmask < b.genmask
+ else
+ return a.proto < b.proto
+ end
+ end
+
+ for k, v in ipairs(data) do
+ if resolve == "1" then
+ hostname = nixio.getnameinfo(v.gateway, nil, 100)
+ if hostname then
+ v.hostname = hostname
+ end
+ end
+ if v.validityTime then
+ v.validityTime = tonumber(string.format("%.0f", v.validityTime / 1000))
+ end
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/hna", {hna=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+function action_mid()
+ local data, has_v4, has_v6, error = fetch_jsoninfo('mid')
+ if error then
+ return
+ end
+
+ local function compare(a,b)
+ if a.proto == b.proto then
+ return a.ipAddress < b.ipAddress
+ else
+ return a.proto < b.proto
+ end
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/mid", {mids=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+function action_smartgw()
+ local data, has_v4, has_v6, error = fetch_jsoninfo('gateways')
+ if error then
+ return
+ end
+
+ local function compare(a,b)
+ if a.proto == b.proto then
+ return a.tcPathCost < b.tcPathCost
+ else
+ return a.proto < b.proto
+ end
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+function action_interfaces()
+ local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
+ if error then
+ return
+ end
+
+ local function compare(a,b)
+ return a.proto < b.proto
+ end
+
+ table.sort(data, compare)
+ luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
+end
+
+-- Internal
+function fetch_jsoninfo(otable)
+ local uci = require "luci.model.uci".cursor_state()
+ local utl = require "luci.util"
+ local json = require "luci.json"
+ local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
+ local jsonreq4 = ""
+ local jsonreq6 = ""
+ jsonreq4 = utl.exec("echo /" .. otable .. " | nc 127.0.0.1 9090")
+ jsonreq6 = utl.exec("echo /" .. otable .. " | nc ::1 9090")
+ local jsondata4 = {}
+ local jsondata6 = {}
+ local data4 = {}
+ local data6 = {}
+ local has_v4 = False
+ local has_v6 = False
+
+ if jsonreq4 == '' and jsonreq6 == '' then
+ luci.template.render("status-olsr/error_olsr")
+ return nil, 0, 0, true
+ end
+
+ if jsonreq4 ~= "" then
+ has_v4 = 1
+ jsondata4 = json.decode(jsonreq4)
+ if otable == 'status' then
+ data4 = jsondata4 or {}
+ else
+ data4 = jsondata4[otable] or {}
+ end
+
+ for k, v in ipairs(data4) do
+ data4[k]['proto'] = '4'
+ end
+
+ end
+ if jsonreq6 ~= "" then
+ has_v6 = 1
+ jsondata6 = json.decode(jsonreq6)
+ if otable == 'status' then
+ data6 = jsondata6 or {}
+ else
+ data6 = jsondata6[otable] or {}
+ end
+ for k, v in ipairs(data6) do
+ data6[k]['proto'] = '6'
+ end
+ end
+
+ for k, v in ipairs(data6) do
+ table.insert(data4, v)
+ end
+
+ return data4, has_v4, has_v6, false
+end
+
diff --git a/applications/luci-app-olsr/luasrc/controller/olsr4.lua b/applications/luci-app-olsr/luasrc/controller/olsr4.lua
new file mode 100644
index 000000000..31a3101bc
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/controller/olsr4.lua
@@ -0,0 +1,47 @@
+module("luci.controller.olsr4", package.seeall)
+
+function index()
+ if not nixio.fs.access("/etc/config/olsrd") then
+ return
+ end
+
+ require("luci.model.uci")
+ local uci = luci.model.uci.cursor_state()
+
+ local ol = entry(
+ {"admin", "services", "olsrd"},
+ cbi("olsr/olsrd"), "OLSR IPv4"
+ )
+ ol.subindex = true
+
+ entry(
+ {"admin", "services", "olsrd", "iface"},
+ cbi("olsr/olsrdiface")
+ ).leaf = true
+
+ entry(
+ {"admin", "services", "olsrd", "hna"},
+ cbi("olsr/olsrdhna"), _("HNA Announcements")
+ )
+
+ oplg = entry(
+ {"admin", "services", "olsrd", "plugins"},
+ cbi("olsr/olsrdplugins"), _("Plugins")
+ )
+
+ oplg.leaf = true
+ oplg.subindex = true
+
+ local uci = require("luci.model.uci").cursor()
+ uci:foreach("olsrd", "LoadPlugin",
+ function (section)
+ local lib = section.library
+ entry(
+ {"admin", "services", "olsrd", "plugins", lib },
+ cbi("olsr/olsrdplugins"),
+ nil --'Plugin "%s"' % lib:gsub("^olsrd_",""):gsub("%.so.+$","")
+ )
+ end
+ )
+end
+
diff --git a/applications/luci-app-olsr/luasrc/controller/olsr6.lua b/applications/luci-app-olsr/luasrc/controller/olsr6.lua
new file mode 100644
index 000000000..9fbaa0427
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/controller/olsr6.lua
@@ -0,0 +1,47 @@
+module("luci.controller.olsr6", package.seeall)
+
+function index()
+ if not nixio.fs.access("/etc/config/olsrd6") then
+ return
+ end
+
+ require("luci.model.uci")
+ local uci = luci.model.uci.cursor_state()
+
+ local ol = entry(
+ {"admin", "services", "olsrd6"},
+ cbi("olsr/olsrd6"), "OLSR IPv6"
+ )
+ ol.subindex = true
+
+ entry(
+ {"admin", "services", "olsrd6", "iface"},
+ cbi("olsr/olsrdiface6")
+ ).leaf = true
+
+ entry(
+ {"admin", "services", "olsrd6", "hna"},
+ cbi("olsr/olsrdhna6"), _("HNA6 Announcements")
+ )
+
+ oplg = entry(
+ {"admin", "services", "olsrd6", "plugins"},
+ cbi("olsr/olsrdplugins6"), _("Plugins")
+ )
+
+ oplg.leaf = true
+ oplg.subindex = true
+
+ local uci = require("luci.model.uci").cursor()
+ uci:foreach("olsrd6", "LoadPlugin",
+ function (section)
+ local lib = section.library
+ entry(
+ {"admin", "services", "olsrd6", "plugins", lib },
+ cbi("olsr/olsrdplugins6"),
+ nil --'Plugin "%s"' % lib:gsub("^olsrd_",""):gsub("%.so.+$","")
+ )
+ end
+ )
+end
+
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd.lua
new file mode 100644
index 000000000..46121747d
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd.lua
@@ -0,0 +1,420 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+require("luci.tools.webadmin")
+local fs = require "nixio.fs"
+local util = require "luci.util"
+local ip = require "luci.ip"
+
+local has_ipip = fs.glob("/etc/modules.d/[0-9]*-ipip")()
+
+m = Map("olsrd", translate("OLSR Daemon"),
+ translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
+ "As such it allows mesh routing for any network equipment. "..
+ "It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
+ "Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
+
+function m.on_parse()
+ local has_defaults = false
+
+ m.uci:foreach("olsrd", "InterfaceDefaults",
+ function(s)
+ has_defaults = true
+ return false
+ end)
+
+ if not has_defaults then
+ m.uci:section("olsrd", "InterfaceDefaults")
+ end
+end
+
+function write_float(self, section, value)
+ local n = tonumber(value)
+ if n ~= nil then
+ return Value.write(self, section, "%.1f" % n)
+ end
+end
+
+s = m:section(TypedSection, "olsrd", translate("General settings"))
+s.anonymous = true
+
+s:tab("general", translate("General Settings"))
+s:tab("lquality", translate("Link Quality Settings"))
+s:tab("smartgw", translate("SmartGW"), not has_ipip and translate("Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it."))
+s:tab("advanced", translate("Advanced Settings"))
+
+ipv = s:taboption("general", ListValue, "IpVersion", translate("Internet protocol"),
+ translate("IP-version to use. If 6and4 is selected then one olsrd instance is started for each protocol."))
+ipv:value("4", "IPv4")
+ipv:value("6and4", "6and4")
+
+
+poll = s:taboption("advanced", Value, "Pollrate", translate("Pollrate"),
+ translate("Polling rate for OLSR sockets in seconds. Default is 0.05."))
+poll.optional = true
+poll.datatype = "ufloat"
+poll.placeholder = "0.05"
+
+nicc = s:taboption("advanced", Value, "NicChgsPollInt", translate("Nic changes poll interval"),
+ translate("Interval to poll network interfaces for configuration changes (in seconds). Default is \"2.5\"."))
+nicc.optional = true
+nicc.datatype = "ufloat"
+nicc.placeholder = "2.5"
+
+tos = s:taboption("advanced", Value, "TosValue", translate("TOS value"),
+ translate("Type of service value for the IP header of control traffic. Default is \"16\"."))
+tos.optional = true
+tos.datatype = "uinteger"
+tos.placeholder = "16"
+
+fib = s:taboption("general", ListValue, "FIBMetric", translate("FIB metric"),
+ translate ("FIBMetric controls the metric value of the host-routes OLSRd sets. "..
+ "\"flat\" means that the metric value is always 2. This is the preferred value "..
+ "because it helps the linux kernel routing to clean up older routes. "..
+ "\"correct\" uses the hopcount as the metric value. "..
+ "\"approx\" use the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. "..
+ "Default is \"flat\"."))
+fib:value("flat")
+fib:value("correct")
+fib:value("approx")
+
+lql = s:taboption("lquality", ListValue, "LinkQualityLevel", translate("LQ level"),
+ translate("Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />"..
+ "<b>0</b> = do not use link quality<br />"..
+ "<b>2</b> = use link quality for MPR selection and routing<br />"..
+ "Default is \"2\""))
+lql:value("2")
+lql:value("0")
+
+lqage = s:taboption("lquality", Value, "LinkQualityAging", translate("LQ aging"),
+ translate("Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values "..
+ "mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)"))
+lqage.optional = true
+lqage:depends("LinkQualityLevel", "2")
+
+lqa = s:taboption("lquality", ListValue, "LinkQualityAlgorithm", translate("LQ algorithm"),
+ translate("Link quality algorithm (only for lq level 2).<br />"..
+ "<b>etx_float</b>: floating point ETX with exponential aging<br />"..
+ "<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />"..
+ "<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />"..
+ "<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />"..
+ "Defaults to \"etx_ff\""))
+lqa.optional = true
+lqa:value("etx_ff")
+lqa:value("etx_fpm")
+lqa:value("etx_float")
+lqa:value("etx_ffeth")
+lqa:depends("LinkQualityLevel", "2")
+lqa.optional = true
+
+lqfish = s:taboption("lquality", Flag, "LinkQualityFishEye", translate("LQ fisheye"),
+ translate("Fisheye mechanism for TCs (checked means on). Default is \"on\""))
+lqfish.default = "1"
+lqfish.optional = true
+
+hyst = s:taboption("lquality", Flag, "UseHysteresis", translate("Use hysteresis"),
+ translate("Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing "..
+ "but delays neighbor registration. Defaults is \"yes\""))
+hyst.default = "yes"
+hyst.enabled = "yes"
+hyst.disabled = "no"
+hyst:depends("LinkQualityLevel", "0")
+hyst.optional = true
+hyst.rmempty = true
+
+port = s:taboption("general", Value, "OlsrPort", translate("Port"),
+ translate("The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535."))
+port.optional = true
+port.default = "698"
+port.rmempty = true
+
+mainip = s:taboption("general", Value, "MainIp", translate("Main IP"),
+ translate("Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. "..
+ "Default is 0.0.0.0, which triggers usage of the IP of the first interface."))
+mainip.optional = true
+mainip.rmempty = true
+mainip.datatype = "ipaddr"
+mainip.placeholder = "0.0.0.0"
+
+sgw = s:taboption("smartgw", Flag, "SmartGateway", translate("Enable"), translate("Enable SmartGateway. If it is disabled, then " ..
+ "all other SmartGateway parameters are ignored. Default is \"no\"."))
+sgw.default="no"
+sgw.enabled="yes"
+sgw.disabled="no"
+sgw.rmempty = true
+
+sgwnat = s:taboption("smartgw", Flag, "SmartGatewayAllowNAT", translate("Allow gateways with NAT"), translate("Allow the selection of an outgoing ipv4 gateway with NAT"))
+sgwnat:depends("SmartGateway", "yes")
+sgwnat.default="yes"
+sgwnat.enabled="yes"
+sgwnat.disabled="no"
+sgwnat.optional = true
+sgwnat.rmempty = true
+
+sgwuplink = s:taboption("smartgw", ListValue, "SmartGatewayUplink", translate("Announce uplink"), translate("Which kind of uplink is exported to the other mesh nodes. " ..
+ "An uplink is detected by looking for a local HNA of 0.0.0.0/0, ::ffff:0:0/96 or 2000::/3. Default setting is \"both\"."))
+sgwuplink:value("none")
+sgwuplink:value("ipv4")
+sgwuplink:value("ipv6")
+sgwuplink:value("both")
+sgwuplink:depends("SmartGateway", "yes")
+sgwuplink.default="both"
+sgwuplink.optional = true
+sgwuplink.rmempty = true
+
+sgwulnat = s:taboption("smartgw", Flag, "SmartGatewayUplinkNAT", translate("Uplink uses NAT"), translate("If this Node uses NAT for connections to the internet. " ..
+ "Default is \"yes\"."))
+sgwulnat:depends("SmartGatewayUplink", "ipv4")
+sgwulnat:depends("SmartGatewayUplink", "both")
+sgwulnat.default="yes"
+sgwulnat.enabled="yes"
+sgwulnat.disabled="no"
+sgwnat.optional = true
+sgwnat.rmempty = true
+
+sgwspeed = s:taboption("smartgw", Value, "SmartGatewaySpeed", translate("Speed of the uplink"), translate("Specifies the speed of "..
+ "the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is \"128 1024\"."))
+sgwspeed:depends("SmartGatewayUplink", "ipv4")
+sgwspeed:depends("SmartGatewayUplink", "ipv6")
+sgwspeed:depends("SmartGatewayUplink", "both")
+sgwspeed.optional = true
+sgwspeed.rmempty = true
+
+sgwprefix = s:taboption("smartgw", Value, "SmartGatewayPrefix", translate("IPv6-Prefix of the uplink"), translate("This can be used " ..
+ "to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " ..
+ "use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. " ..
+ "Default is \"::/0\" (no prefix)."))
+sgwprefix:depends("SmartGatewayUplink", "ipv6")
+sgwprefix:depends("SmartGatewayUplink", "both")
+sgwprefix.optional = true
+sgwprefix.rmempty = true
+
+willingness = s:taboption("advanced", ListValue, "Willingness", translate("Willingness"),
+ translate("The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is \"3\"."))
+for i=0,7 do
+ willingness:value(i)
+end
+willingness.optional = true
+willingness.default = "3"
+
+natthr = s:taboption("advanced", Value, "NatThreshold", translate("NAT threshold"),
+ translate("If the route to the current gateway is to be changed, the ETX value of this gateway is "..
+ "multiplied with this value before it is compared to the new one. "..
+ "The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />"..
+ "<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />"..
+ "Defaults to \"1.0\"."))
+for i=1,0.1,-0.1 do
+ natthr:value(i)
+end
+natthr:depends("LinkQualityAlgorithm", "etx_ff")
+natthr:depends("LinkQualityAlgorithm", "etx_float")
+natthr:depends("LinkQualityAlgorithm", "etx_fpm")
+natthr.default = "1.0"
+natthr.optional = true
+natthr.write = write_float
+
+
+i = m:section(TypedSection, "InterfaceDefaults", translate("Interfaces Defaults"))
+i.anonymous = true
+i.addremove = false
+
+i:tab("general", translate("General Settings"))
+i:tab("addrs", translate("IP Addresses"))
+i:tab("timing", translate("Timing and Validity"))
+
+mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
+ translate("Interface Mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
+ "valid Modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
+mode:value("mesh")
+mode:value("ether")
+mode.optional = true
+mode.rmempty = true
+
+
+weight = i:taboption("general", Value, "Weight", translate("Weight"),
+ translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
+ "Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
+ "but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
+ "<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
+ "For any other value of LinkQualityLevel, the interface ETX value is used instead."))
+weight.optional = true
+weight.datatype = "uinteger"
+weight.placeholder = "0"
+
+lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
+ translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
+ "It is only used when LQ-Level is greater than 0. Examples:<br />"..
+ "reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />"..
+ "reduce LQ to all nodes on this interface by 20%: default 0.8"))
+lqmult.optional = true
+lqmult.rmempty = true
+lqmult.cast = "table"
+lqmult.placeholder = "default 1.0"
+
+function lqmult.validate(self, value)
+ for _, v in pairs(value) do
+ if v ~= "" then
+ local val = util.split(v, " ")
+ local host = val[1]
+ local mult = val[2]
+ if not host or not mult then
+ return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) seperated by space.")
+ end
+ if not (host == "default" or ip.IPv4(host) or ip.IPv6(host)) then
+ return nil, translate("Can only be a valid IPv4 or IPv6 address or 'default'")
+ end
+ if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
+ return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
+ end
+ if not mult:match("[0-1]%.[0-9]+") then
+ return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
+ end
+ end
+ end
+ return value
+end
+
+ip4b = i:taboption("addrs", Value, "Ip4Broadcast", translate("IPv4 broadcast"),
+ translate("IPv4 broadcast address for outgoing OLSR packets. One useful example would be 255.255.255.255. "..
+ "Default is \"0.0.0.0\", which triggers the usage of the interface broadcast IP."))
+ip4b.optional = true
+ip4b.datatype = "ip4addr"
+ip4b.placeholder = "0.0.0.0"
+
+ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
+ translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
+ip6m.optional = true
+ip6m.datatype = "ip6addr"
+ip6m.placeholder = "FF02::6D"
+
+ip4s = i:taboption("addrs", Value, "IPv4Src", translate("IPv4 source"),
+ translate("IPv4 src address for outgoing OLSR packages. Default is \"0.0.0.0\", which triggers usage of the interface IP."))
+ip4s.optional = true
+ip4s.datatype = "ip4addr"
+ip4s.placeholder = "0.0.0.0"
+
+ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
+ translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
+ "Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
+ip6s.optional = true
+ip6s.datatype = "ip6addr"
+ip6s.placeholder = "0::/0"
+
+
+hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
+hi.optional = true
+hi.datatype = "ufloat"
+hi.placeholder = "5.0"
+hi.write = write_float
+
+hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
+hv.optional = true
+hv.datatype = "ufloat"
+hv.placeholder = "40.0"
+hv.write = write_float
+
+ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
+ti.optional = true
+ti.datatype = "ufloat"
+ti.placeholder = "2.0"
+ti.write = write_float
+
+tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
+tv.optional = true
+tv.datatype = "ufloat"
+tv.placeholder = "256.0"
+tv.write = write_float
+
+mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
+mi.optional = true
+mi.datatype = "ufloat"
+mi.placeholder = "18.0"
+mi.write = write_float
+
+mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
+mv.optional = true
+mv.datatype = "ufloat"
+mv.placeholder = "324.0"
+mv.write = write_float
+
+ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
+ai.optional = true
+ai.datatype = "ufloat"
+ai.placeholder = "18.0"
+ai.write = write_float
+
+av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
+av.optional = true
+av.datatype = "ufloat"
+av.placeholder = "108.0"
+av.write = write_float
+
+
+ifs = m:section(TypedSection, "Interface", translate("Interfaces"))
+ifs.addremove = true
+ifs.anonymous = true
+ifs.extedit = luci.dispatcher.build_url("admin/services/olsrd/iface/%s")
+ifs.template = "cbi/tblsection"
+
+function ifs.create(...)
+ local sid = TypedSection.create(...)
+ luci.http.redirect(ifs.extedit % sid)
+end
+
+ign = ifs:option(Flag, "ignore", translate("Enable"))
+ign.enabled = "0"
+ign.disabled = "1"
+ign.rmempty = false
+function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+end
+
+network = ifs:option(DummyValue, "interface", translate("Network"))
+network.template = "cbi/network_netinfo"
+
+mode = ifs:option(DummyValue, "Mode", translate("Mode"))
+function mode.cfgvalue(...)
+ return Value.cfgvalue(...) or m.uci:get_first("olsrd", "InterfaceDefaults", "Mode", "mesh")
+end
+
+hello = ifs:option(DummyValue, "_hello", translate("Hello"))
+function hello.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd", section, "HelloInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HelloInterval", 5))
+ local v = tonumber(m.uci:get("olsrd", section, "HelloValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HelloValidityTime", 40))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+tc = ifs:option(DummyValue, "_tc", translate("TC"))
+function tc.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd", section, "TcInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "TcInterval", 2))
+ local v = tonumber(m.uci:get("olsrd", section, "TcValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "TcValidityTime", 256))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+mid = ifs:option(DummyValue, "_mid", translate("MID"))
+function mid.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd", section, "MidInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "MidInterval", 18))
+ local v = tonumber(m.uci:get("olsrd", section, "MidValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "MidValidityTime", 324))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+hna = ifs:option(DummyValue, "_hna", translate("HNA"))
+function hna.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd", section, "HnaInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HnaInterval", 18))
+ local v = tonumber(m.uci:get("olsrd", section, "HnaValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HnaValidityTime", 108))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+return m
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd6.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd6.lua
new file mode 100644
index 000000000..2b8d60cd1
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrd6.lua
@@ -0,0 +1,401 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+require("luci.tools.webadmin")
+local fs = require "nixio.fs"
+local util = require "luci.util"
+local ip = require "luci.ip"
+
+local has_ipip = fs.glob("/etc/modules.d/[0-9]*-ipip")()
+
+m = Map("olsrd6", translate("OLSR Daemon"),
+ translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
+ "As such it allows mesh routing for any network equipment. "..
+ "It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
+ "Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
+
+function m.on_parse()
+ local has_defaults = false
+
+ m.uci:foreach("olsrd6", "InterfaceDefaults",
+ function(s)
+ has_defaults = true
+ return false
+ end)
+
+ if not has_defaults then
+ m.uci:section("olsrd6", "InterfaceDefaults")
+ end
+end
+
+function write_float(self, section, value)
+ local n = tonumber(value)
+ if n ~= nil then
+ return Value.write(self, section, "%.1f" % n)
+ end
+end
+
+s = m:section(TypedSection, "olsrd6", translate("General settings"))
+s.anonymous = true
+
+s:tab("general", translate("General Settings"))
+s:tab("lquality", translate("Link Quality Settings"))
+s:tab("smartgw", translate("SmartGW"), not has_ipip and translate("Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it."))
+s:tab("advanced", translate("Advanced Settings"))
+
+poll = s:taboption("advanced", Value, "Pollrate", translate("Pollrate"),
+ translate("Polling rate for OLSR sockets in seconds. Default is 0.05."))
+poll.optional = true
+poll.datatype = "ufloat"
+poll.placeholder = "0.05"
+
+nicc = s:taboption("advanced", Value, "NicChgsPollInt", translate("Nic changes poll interval"),
+ translate("Interval to poll network interfaces for configuration changes (in seconds). Default is \"2.5\"."))
+nicc.optional = true
+nicc.datatype = "ufloat"
+nicc.placeholder = "2.5"
+
+tos = s:taboption("advanced", Value, "TosValue", translate("TOS value"),
+ translate("Type of service value for the IP header of control traffic. Default is \"16\"."))
+tos.optional = true
+tos.datatype = "uinteger"
+tos.placeholder = "16"
+
+fib = s:taboption("general", ListValue, "FIBMetric", translate("FIB metric"),
+ translate ("FIBMetric controls the metric value of the host-routes OLSRd sets. "..
+ "\"flat\" means that the metric value is always 2. This is the preferred value "..
+ "because it helps the linux kernel routing to clean up older routes. "..
+ "\"correct\" uses the hopcount as the metric value. "..
+ "\"approx\" use the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. "..
+ "Default is \"flat\"."))
+fib:value("flat")
+fib:value("correct")
+fib:value("approx")
+
+lql = s:taboption("lquality", ListValue, "LinkQualityLevel", translate("LQ level"),
+ translate("Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />"..
+ "<b>0</b> = do not use link quality<br />"..
+ "<b>2</b> = use link quality for MPR selection and routing<br />"..
+ "Default is \"2\""))
+lql:value("2")
+lql:value("0")
+
+lqage = s:taboption("lquality", Value, "LinkQualityAging", translate("LQ aging"),
+ translate("Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values "..
+ "mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)"))
+lqage.optional = true
+lqage:depends("LinkQualityLevel", "2")
+
+lqa = s:taboption("lquality", ListValue, "LinkQualityAlgorithm", translate("LQ algorithm"),
+ translate("Link quality algorithm (only for lq level 2).<br />"..
+ "<b>etx_float</b>: floating point ETX with exponential aging<br />"..
+ "<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />"..
+ "<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />"..
+ "<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />"..
+ "Defaults to \"etx_ff\""))
+lqa.optional = true
+lqa:value("etx_ff")
+lqa:value("etx_fpm")
+lqa:value("etx_float")
+lqa:value("etx_ffeth")
+lqa:depends("LinkQualityLevel", "2")
+lqa.optional = true
+
+lqfish = s:taboption("lquality", Flag, "LinkQualityFishEye", translate("LQ fisheye"),
+ translate("Fisheye mechanism for TCs (checked means on). Default is \"on\""))
+lqfish.default = "1"
+lqfish.optional = true
+
+hyst = s:taboption("lquality", Flag, "UseHysteresis", translate("Use hysteresis"),
+ translate("Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing "..
+ "but delays neighbor registration. Defaults is \"yes\""))
+hyst.default = "yes"
+hyst.enabled = "yes"
+hyst.disabled = "no"
+hyst:depends("LinkQualityLevel", "0")
+hyst.optional = true
+hyst.rmempty = true
+
+port = s:taboption("general", Value, "OlsrPort", translate("Port"),
+ translate("The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535."))
+port.optional = true
+port.default = "698"
+port.rmempty = true
+
+mainip = s:taboption("general", Value, "MainIp", translate("Main IP"),
+ translate("Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. "..
+ "Default is ::, which triggers usage of the IP of the first interface."))
+mainip.optional = true
+mainip.rmempty = true
+mainip.datatype = "ipaddr"
+mainip.placeholder = "::"
+
+sgw = s:taboption("smartgw", Flag, "SmartGateway", translate("Enable"), translate("Enable SmartGateway. If it is disabled, then " ..
+ "all other SmartGateway parameters are ignored. Default is \"no\"."))
+sgw.default="no"
+sgw.enabled="yes"
+sgw.disabled="no"
+sgw.rmempty = true
+
+sgwnat = s:taboption("smartgw", Flag, "SmartGatewayAllowNAT", translate("Allow gateways with NAT"), translate("Allow the selection of an outgoing ipv4 gateway with NAT"))
+sgwnat:depends("SmartGateway", "yes")
+sgwnat.default="yes"
+sgwnat.enabled="yes"
+sgwnat.disabled="no"
+sgwnat.optional = true
+sgwnat.rmempty = true
+
+sgwuplink = s:taboption("smartgw", ListValue, "SmartGatewayUplink", translate("Announce uplink"), translate("Which kind of uplink is exported to the other mesh nodes. " ..
+ "An uplink is detected by looking for a local HNA6 ::ffff:0:0/96 or 2000::/3. Default setting is \"both\"."))
+sgwuplink:value("none")
+sgwuplink:value("ipv4")
+sgwuplink:value("ipv6")
+sgwuplink:value("both")
+sgwuplink:depends("SmartGateway", "yes")
+sgwuplink.default="both"
+sgwuplink.optional = true
+sgwuplink.rmempty = true
+
+sgwulnat = s:taboption("smartgw", Flag, "SmartGatewayUplinkNAT", translate("Uplink uses NAT"), translate("If this Node uses NAT for connections to the internet. " ..
+ "Default is \"yes\"."))
+sgwulnat:depends("SmartGatewayUplink", "ipv4")
+sgwulnat:depends("SmartGatewayUplink", "both")
+sgwulnat.default="yes"
+sgwulnat.enabled="yes"
+sgwulnat.disabled="no"
+sgwnat.optional = true
+sgwnat.rmempty = true
+
+sgwspeed = s:taboption("smartgw", Value, "SmartGatewaySpeed", translate("Speed of the uplink"), translate("Specifies the speed of "..
+ "the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is \"128 1024\"."))
+sgwspeed:depends("SmartGatewayUplink", "ipv4")
+sgwspeed:depends("SmartGatewayUplink", "ipv6")
+sgwspeed:depends("SmartGatewayUplink", "both")
+sgwspeed.optional = true
+sgwspeed.rmempty = true
+
+sgwprefix = s:taboption("smartgw", Value, "SmartGatewayPrefix", translate("IPv6-Prefix of the uplink"), translate("This can be used " ..
+ "to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " ..
+ "use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. " ..
+ "Default is \"::/0\" (no prefix)."))
+sgwprefix:depends("SmartGatewayUplink", "ipv6")
+sgwprefix:depends("SmartGatewayUplink", "both")
+sgwprefix.optional = true
+sgwprefix.rmempty = true
+
+willingness = s:taboption("advanced", ListValue, "Willingness", translate("Willingness"),
+ translate("The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is \"3\"."))
+for i=0,7 do
+ willingness:value(i)
+end
+willingness.optional = true
+willingness.default = "3"
+
+natthr = s:taboption("advanced", Value, "NatThreshold", translate("NAT threshold"),
+ translate("If the route to the current gateway is to be changed, the ETX value of this gateway is "..
+ "multiplied with this value before it is compared to the new one. "..
+ "The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />"..
+ "<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />"..
+ "Defaults to \"1.0\"."))
+for i=1,0.1,-0.1 do
+ natthr:value(i)
+end
+natthr:depends("LinkQualityAlgorithm", "etx_ff")
+natthr:depends("LinkQualityAlgorithm", "etx_float")
+natthr:depends("LinkQualityAlgorithm", "etx_fpm")
+natthr.default = "1.0"
+natthr.optional = true
+natthr.write = write_float
+
+
+i = m:section(TypedSection, "InterfaceDefaults", translate("Interfaces Defaults"))
+i.anonymous = true
+i.addremove = false
+
+i:tab("general", translate("General Settings"))
+i:tab("addrs", translate("IP Addresses"))
+i:tab("timing", translate("Timing and Validity"))
+
+mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
+ translate("Interface Mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
+ "valid Modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
+mode:value("mesh")
+mode:value("ether")
+mode.optional = true
+mode.rmempty = true
+
+
+weight = i:taboption("general", Value, "Weight", translate("Weight"),
+ translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
+ "Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
+ "but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
+ "<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
+ "For any other value of LinkQualityLevel, the interface ETX value is used instead."))
+weight.optional = true
+weight.datatype = "uinteger"
+weight.placeholder = "0"
+
+lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
+ translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
+ "It is only used when LQ-Level is greater than 0. Examples:<br />"..
+ "reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />"..
+ "reduce LQ to all nodes on this interface by 20%: default 0.8"))
+lqmult.optional = true
+lqmult.rmempty = true
+lqmult.cast = "table"
+lqmult.placeholder = "default 1.0"
+
+function lqmult.validate(self, value)
+ for _, v in pairs(value) do
+ if v ~= "" then
+ local val = util.split(v, " ")
+ local host = val[1]
+ local mult = val[2]
+ if not host or not mult then
+ return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) seperated by space.")
+ end
+ if not (host == "default" or ip.IPv6(host)) then
+ return nil, translate("Can only be a valid IPv6 address or 'default'")
+ end
+ if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
+ return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
+ end
+ if not mult:match("[0-1]%.[0-9]+") then
+ return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
+ end
+ end
+ end
+ return value
+end
+
+ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
+ translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
+ip6m.optional = true
+ip6m.datatype = "ip6addr"
+ip6m.placeholder = "FF02::6D"
+
+ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
+ translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
+ "Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
+ip6s.optional = true
+ip6s.datatype = "ip6addr"
+ip6s.placeholder = "0::/0"
+
+
+hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
+hi.optional = true
+hi.datatype = "ufloat"
+hi.placeholder = "5.0"
+hi.write = write_float
+
+hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
+hv.optional = true
+hv.datatype = "ufloat"
+hv.placeholder = "40.0"
+hv.write = write_float
+
+ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
+ti.optional = true
+ti.datatype = "ufloat"
+ti.placeholder = "2.0"
+ti.write = write_float
+
+tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
+tv.optional = true
+tv.datatype = "ufloat"
+tv.placeholder = "256.0"
+tv.write = write_float
+
+mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
+mi.optional = true
+mi.datatype = "ufloat"
+mi.placeholder = "18.0"
+mi.write = write_float
+
+mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
+mv.optional = true
+mv.datatype = "ufloat"
+mv.placeholder = "324.0"
+mv.write = write_float
+
+ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
+ai.optional = true
+ai.datatype = "ufloat"
+ai.placeholder = "18.0"
+ai.write = write_float
+
+av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
+av.optional = true
+av.datatype = "ufloat"
+av.placeholder = "108.0"
+av.write = write_float
+
+
+ifs = m:section(TypedSection, "Interface", translate("Interfaces"))
+ifs.addremove = true
+ifs.anonymous = true
+ifs.extedit = luci.dispatcher.build_url("admin/services/olsrd6/iface/%s")
+ifs.template = "cbi/tblsection"
+
+function ifs.create(...)
+ local sid = TypedSection.create(...)
+ luci.http.redirect(ifs.extedit % sid)
+end
+
+ign = ifs:option(Flag, "ignore", translate("Enable"))
+ign.enabled = "0"
+ign.disabled = "1"
+ign.rmempty = false
+function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+end
+
+network = ifs:option(DummyValue, "interface", translate("Network"))
+network.template = "cbi/network_netinfo"
+
+mode = ifs:option(DummyValue, "Mode", translate("Mode"))
+function mode.cfgvalue(...)
+ return Value.cfgvalue(...) or m.uci:get_first("olsrd6", "InterfaceDefaults", "Mode", "mesh")
+end
+
+hello = ifs:option(DummyValue, "_hello", translate("Hello"))
+function hello.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd6", section, "HelloInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HelloInterval", 5))
+ local v = tonumber(m.uci:get("olsrd6", section, "HelloValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HelloValidityTime", 40))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+tc = ifs:option(DummyValue, "_tc", translate("TC"))
+function tc.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd6", section, "TcInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "TcInterval", 2))
+ local v = tonumber(m.uci:get("olsrd6", section, "TcValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "TcValidityTime", 256))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+mid = ifs:option(DummyValue, "_mid", translate("MID"))
+function mid.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd6", section, "MidInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "MidInterval", 18))
+ local v = tonumber(m.uci:get("olsrd6", section, "MidValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "MidValidityTime", 324))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+hna = ifs:option(DummyValue, "_hna", translate("HNA"))
+function hna.cfgvalue(self, section)
+ local i = tonumber(m.uci:get("olsrd6", section, "HnaInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HnaInterval", 18))
+ local v = tonumber(m.uci:get("olsrd6", section, "HnaValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HnaValidityTime", 108))
+ return "%.01fs / %.01fs" %{ i, v }
+end
+
+return m
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrddisplay.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrddisplay.lua
new file mode 100644
index 000000000..48dc965c7
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrddisplay.lua
@@ -0,0 +1,23 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2011 Manuel Munz <freifunk at somakoma de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+]]--
+
+m = Map("luci_olsr", translate("OLSR - Display Options"))
+
+s = m:section(TypedSection, "olsr")
+s.anonymous = true
+
+res = s:option(Flag, "resolve", translate("Resolve"),
+ translate("Resolve hostnames on status pages. It is generally safe to allow this, but if you use public IPs and have unstable DNS-Setup then those pages will load really slow. In this case disable it here."))
+res.default = "0"
+res.optional = true
+
+return m
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna.lua
new file mode 100644
index 000000000..d5ee79f24
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna.lua
@@ -0,0 +1,56 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local uci = require "luci.model.uci".cursor()
+local ipv = uci:get_first("olsrd", "olsrd", "IpVersion", "4")
+
+mh = Map("olsrd", translate("OLSR - HNA-Announcements"), translate("Hosts in a OLSR routed network can announce connecitivity " ..
+ "to external networks using HNA messages."))
+
+if ipv == "6and4" or ipv == "4" then
+ hna4 = mh:section(TypedSection, "Hna4", translate("Hna4"), translate("Both values must use the dotted decimal notation."))
+ hna4.addremove = true
+ hna4.anonymous = true
+ hna4.template = "cbi/tblsection"
+
+ net4 = hna4:option(Value, "netaddr", translate("Network address"))
+ net4.datatype = "ip4addr"
+ net4.placeholder = "10.11.12.13"
+ net4.default = "10.11.12.13"
+ msk4 = hna4:option(Value, "netmask", translate("Netmask"))
+ msk4.datatype = "ip4addr"
+ msk4.placeholder = "255.255.255.255"
+ msk4.default = "255.255.255.255"
+end
+
+if ipv == "6and4" or ipv == "6" then
+ hna6 = mh:section(TypedSection, "Hna6", translate("Hna6"), translate("IPv6 network must be given in full notation, " ..
+ "prefix must be in CIDR notation."))
+ hna6.addremove = true
+ hna6.anonymous = true
+ hna6.template = "cbi/tblsection"
+
+ net6 = hna6:option(Value, "netaddr", translate("Network address"))
+ net6.datatype = "ip6addr"
+ net6.placeholder = "fec0:2200:106:0:0:0:0:0"
+ net6.default = "fec0:2200:106:0:0:0:0:0"
+ msk6 = hna6:option(Value, "prefix", translate("Prefix"))
+ msk6.datatype = "range(0,128)"
+ msk6.placeholder = "128"
+ msk6.default = "128"
+end
+
+return mh
+
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna6.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna6.lua
new file mode 100644
index 000000000..21b2ec867
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdhna6.lua
@@ -0,0 +1,36 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local uci = require "luci.model.uci".cursor()
+
+mh = Map("olsrd6", translate("OLSR - HNA6-Announcements"), translate("Hosts in a OLSR routed network can announce connecitivity " ..
+ "to external networks using HNA6 messages."))
+
+ hna6 = mh:section(TypedSection, "Hna6", translate("Hna6"), translate("IPv6 network must be given in full notation, " ..
+ "prefix must be in CIDR notation."))
+ hna6.addremove = true
+ hna6.anonymous = true
+ hna6.template = "cbi/tblsection"
+
+ net6 = hna6:option(Value, "netaddr", translate("Network address"))
+ net6.datatype = "ip6addr"
+ net6.placeholder = "fec0:2200:106:0:0:0:0:0"
+ net6.default = "fec0:2200:106:0:0:0:0:0"
+ msk6 = hna6:option(Value, "prefix", translate("Prefix"))
+ msk6.datatype = "range(0,128)"
+ msk6.placeholder = "128"
+ msk6.default = "128"
+return mh
+
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface.lua
new file mode 100644
index 000000000..9673d9afc
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface.lua
@@ -0,0 +1,189 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
+]]--
+
+local util = require "luci.util"
+local ip = require "luci.ip"
+
+function write_float(self, section, value)
+ local n = tonumber(value)
+ if n ~= nil then
+ return Value.write(self, section, "%.1f" % n)
+ end
+end
+
+m = Map("olsrd", translate("OLSR Daemon - Interface"),
+ translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
+ "As such it allows mesh routing for any network equipment. "..
+ "It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
+ "Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
+
+m.redirect = luci.dispatcher.build_url("admin/services/olsrd")
+
+if not arg[1] or m.uci:get("olsrd", arg[1]) ~= "Interface" then
+ luci.http.redirect(m.redirect)
+ return
+end
+
+i = m:section(NamedSection, arg[1], "Interface", translate("Interface"))
+i.anonymous = true
+i.addremove = false
+
+i:tab("general", translate("General Settings"))
+i:tab("addrs", translate("IP Addresses"))
+i:tab("timing", translate("Timing and Validity"))
+
+ign = i:taboption("general", Flag, "ignore", translate("Enable"),
+ translate("Enable this interface."))
+ign.enabled = "0"
+ign.disabled = "1"
+ign.rmempty = false
+function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+end
+
+network = i:taboption("general", Value, "interface", translate("Network"),
+ translate("The interface OLSRd should serve."))
+
+network.template = "cbi/network_netlist"
+network.widget = "radio"
+network.nocreate = true
+
+mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
+ translate("Interface Mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
+ "valid Modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
+mode:value("mesh")
+mode:value("ether")
+mode.optional = true
+mode.rmempty = true
+
+
+weight = i:taboption("general", Value, "Weight", translate("Weight"),
+ translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
+ "Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
+ "but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
+ "<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
+ "For any other value of LinkQualityLevel, the interface ETX value is used instead."))
+weight.optional = true
+weight.datatype = "uinteger"
+weight.placeholder = "0"
+
+lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
+ translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
+ "It is only used when LQ-Level is greater than 0. Examples:<br />"..
+ "reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />"..
+ "reduce LQ to all nodes on this interface by 20%: default 0.8"))
+lqmult.optional = true
+lqmult.rmempty = true
+lqmult.cast = "table"
+lqmult.placeholder = "default 1.0"
+
+function lqmult.validate(self, value)
+ for _, v in pairs(value) do
+ if v ~= "" then
+ local val = util.split(v, " ")
+ local host = val[1]
+ local mult = val[2]
+ if not host or not mult then
+ return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) seperated by space.")
+ end
+ if not (host == "default" or ip.IPv4(host) or ip.IPv6(host)) then
+ return nil, translate("Can only be a valid IPv4 or IPv6 address or 'default'")
+ end
+ if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
+ return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
+ end
+ if not mult:match("[0-1]%.[0-9]+") then
+ return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
+ end
+ end
+ end
+ return value
+end
+
+ip4b = i:taboption("addrs", Value, "Ip4Broadcast", translate("IPv4 broadcast"),
+ translate("IPv4 broadcast address for outgoing OLSR packets. One useful example would be 255.255.255.255. "..
+ "Default is \"0.0.0.0\", which triggers the usage of the interface broadcast IP."))
+ip4b.optional = true
+ip4b.datatype = "ip4addr"
+ip4b.placeholder = "0.0.0.0"
+
+ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
+ translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
+ip6m.optional = true
+ip6m.datatype = "ip6addr"
+ip6m.placeholder = "FF02::6D"
+
+ip4s = i:taboption("addrs", Value, "IPv4Src", translate("IPv4 source"),
+ translate("IPv4 src address for outgoing OLSR packages. Default is \"0.0.0.0\", which triggers usage of the interface IP."))
+ip4s.optional = true
+ip4s.datatype = "ip4addr"
+ip4s.placeholder = "0.0.0.0"
+
+ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
+ translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
+ "Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
+ip6s.optional = true
+ip6s.datatype = "ip6addr"
+ip6s.placeholder = "0::/0"
+
+hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
+hi.optional = true
+hi.datatype = "ufloat"
+hi.placeholder = "5.0"
+hi.write = write_float
+
+hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
+hv.optional = true
+hv.datatype = "ufloat"
+hv.placeholder = "40.0"
+hv.write = write_float
+
+ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
+ti.optional = true
+ti.datatype = "ufloat"
+ti.placeholder = "2.0"
+ti.write = write_float
+
+tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
+tv.optional = true
+tv.datatype = "ufloat"
+tv.placeholder = "256.0"
+tv.write = write_float
+
+mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
+mi.optional = true
+mi.datatype = "ufloat"
+mi.placeholder = "18.0"
+mi.write = write_float
+
+mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
+mv.optional = true
+mv.datatype = "ufloat"
+mv.placeholder = "324.0"
+mv.write = write_float
+
+ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
+ai.optional = true
+ai.datatype = "ufloat"
+ai.placeholder = "18.0"
+ai.write = write_float
+
+av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
+av.optional = true
+av.datatype = "ufloat"
+av.placeholder = "108.0"
+av.write = write_float
+
+return m
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface6.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface6.lua
new file mode 100644
index 000000000..85818acb3
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdiface6.lua
@@ -0,0 +1,176 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
+]]--
+
+local util = require "luci.util"
+local ip = require "luci.ip"
+
+function write_float(self, section, value)
+ local n = tonumber(value)
+ if n ~= nil then
+ return Value.write(self, section, "%.1f" % n)
+ end
+end
+
+m = Map("olsrd6", translate("OLSR Daemon - Interface"),
+ translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
+ "As such it allows mesh routing for any network equipment. "..
+ "It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
+ "Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
+
+m.redirect = luci.dispatcher.build_url("admin/services/olsrd6")
+
+if not arg[1] or m.uci:get("olsrd6", arg[1]) ~= "Interface" then
+ luci.http.redirect(m.redirect)
+ return
+end
+
+i = m:section(NamedSection, arg[1], "Interface", translate("Interface"))
+i.anonymous = true
+i.addremove = false
+
+i:tab("general", translate("General Settings"))
+i:tab("addrs", translate("IP Addresses"))
+i:tab("timing", translate("Timing and Validity"))
+
+ign = i:taboption("general", Flag, "ignore", translate("Enable"),
+ translate("Enable this interface."))
+ign.enabled = "0"
+ign.disabled = "1"
+ign.rmempty = false
+function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+end
+
+network = i:taboption("general", Value, "interface", translate("Network"),
+ translate("The interface OLSRd should serve."))
+
+network.template = "cbi/network_netlist"
+network.widget = "radio"
+network.nocreate = true
+
+mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
+ translate("Interface Mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
+ "valid Modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
+mode:value("mesh")
+mode:value("ether")
+mode.optional = true
+mode.rmempty = true
+
+
+weight = i:taboption("general", Value, "Weight", translate("Weight"),
+ translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
+ "Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
+ "but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
+ "<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
+ "For any other value of LinkQualityLevel, the interface ETX value is used instead."))
+weight.optional = true
+weight.datatype = "uinteger"
+weight.placeholder = "0"
+
+lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
+ translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
+ "It is only used when LQ-Level is greater than 0. Examples:<br />"..
+ "reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />"..
+ "reduce LQ to all nodes on this interface by 20%: default 0.8"))
+lqmult.optional = true
+lqmult.rmempty = true
+lqmult.cast = "table"
+lqmult.placeholder = "default 1.0"
+
+function lqmult.validate(self, value)
+ for _, v in pairs(value) do
+ if v ~= "" then
+ local val = util.split(v, " ")
+ local host = val[1]
+ local mult = val[2]
+ if not host or not mult then
+ return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) seperated by space.")
+ end
+ if not (host == "default" or ip.IPv6(host)) then
+ return nil, translate("Can only be a valid IPv6 address or 'default'")
+ end
+ if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
+ return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
+ end
+ if not mult:match("[0-1]%.[0-9]+") then
+ return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
+ end
+ end
+ end
+ return value
+end
+
+ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
+ translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
+ip6m.optional = true
+ip6m.datatype = "ip6addr"
+ip6m.placeholder = "FF02::6D"
+
+ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
+ translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
+ "Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
+ip6s.optional = true
+ip6s.datatype = "ip6addr"
+ip6s.placeholder = "0::/0"
+
+hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
+hi.optional = true
+hi.datatype = "ufloat"
+hi.placeholder = "5.0"
+hi.write = write_float
+
+hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
+hv.optional = true
+hv.datatype = "ufloat"
+hv.placeholder = "40.0"
+hv.write = write_float
+
+ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
+ti.optional = true
+ti.datatype = "ufloat"
+ti.placeholder = "2.0"
+ti.write = write_float
+
+tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
+tv.optional = true
+tv.datatype = "ufloat"
+tv.placeholder = "256.0"
+tv.write = write_float
+
+mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
+mi.optional = true
+mi.datatype = "ufloat"
+mi.placeholder = "18.0"
+mi.write = write_float
+
+mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
+mv.optional = true
+mv.datatype = "ufloat"
+mv.placeholder = "324.0"
+mv.write = write_float
+
+ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
+ai.optional = true
+ai.datatype = "ufloat"
+ai.placeholder = "18.0"
+ai.write = write_float
+
+av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
+av.optional = true
+av.datatype = "ufloat"
+av.placeholder = "108.0"
+av.write = write_float
+
+return m
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua
new file mode 100644
index 000000000..bd72c56ad
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua
@@ -0,0 +1,270 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local ip = require "luci.ip"
+local fs = require "nixio.fs"
+
+if arg[1] then
+ mp = Map("olsrd", translate("OLSR - Plugins"))
+
+ p = mp:section(TypedSection, "LoadPlugin", translate("Plugin configuration"))
+ p:depends("library", arg[1])
+ p.anonymous = true
+
+ ign = p:option(Flag, "ignore", translate("Enable"))
+ ign.enabled = "0"
+ ign.disabled = "1"
+ ign.rmempty = false
+ function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+ end
+
+ lib = p:option(DummyValue, "library", translate("Library"))
+ lib.default = arg[1]
+
+ local function Range(x,y)
+ local t = {}
+ for i = x, y do t[#t+1] = i end
+ return t
+ end
+
+ local function Cidr2IpMask(val)
+ if val then
+ for i = 1, #val do
+ local cidr = ip.IPv4(val[i]) or ip.IPv6(val[i])
+ if cidr then
+ val[i] = cidr:network():string() .. " " .. cidr:mask():string()
+ end
+ end
+ return val
+ end
+ end
+
+ local function IpMask2Cidr(val)
+ if val then
+ for i = 1, #val do
+ local ip, mask = val[i]:gmatch("([^%s]+)%s+([^%s]+)")()
+ local cidr
+ if ip and mask and ip:match(":") then
+ cidr = ip.IPv6(ip, mask)
+ elseif ip and mask then
+ cidr = ip.IPv4(ip, mask)
+ end
+
+ if cidr then
+ val[i] = cidr:string()
+ end
+ end
+ return val
+ end
+ end
+
+
+ local knownPlParams = {
+ ["olsrd_bmf.so.1.5.3"] = {
+ { Value, "BmfInterface", "bmf0" },
+ { Value, "BmfInterfaceIp", "10.10.10.234/24" },
+ { Flag, "DoLocalBroadcast", "no" },
+ { Flag, "CapturePacketsOnOlsrInterfaces", "yes" },
+ { ListValue, "BmfMechanism", { "UnicastPromiscuous", "Broadcast" } },
+ { Value, "BroadcastRetransmitCount", "2" },
+ { Value, "FanOutLimit", "4" },
+ { DynamicList, "NonOlsrIf", "br-lan" }
+ },
+
+ ["olsrd_dyn_gw.so.0.4"] = {
+ { Value, "Interval", "40" },
+ { DynamicList, "Ping", "141.1.1.1" },
+ { DynamicList, "HNA", "192.168.80.0/24", IpMask2Cidr, Cidr2IpMask }
+ },
+
+ ["olsrd_httpinfo.so.0.1"] = {
+ { Value, "port", "80" },
+ { DynamicList, "Host", "163.24.87.3" },
+ { DynamicList, "Net", "0.0.0.0/0", Cidr2IpMask }
+ },
+
+ ["olsrd_nameservice.so.0.3"] = {
+ { DynamicList, "name", "my-name.mesh" },
+ { DynamicList, "hosts", "1.2.3.4 name-for-other-interface.mesh" },
+ { Value, "suffix", ".olsr" },
+ { Value, "hosts_file", "/path/to/hosts_file" },
+ { Value, "add_hosts", "/path/to/file" },
+ { Value, "dns_server", "141.1.1.1" },
+ { Value, "resolv_file", "/path/to/resolv.conf" },
+ { Value, "interval", "120" },
+ { Value, "timeout", "240" },
+ { Value, "lat", "12.123" },
+ { Value, "lon", "12.123" },
+ { Value, "latlon_file", "/var/run/latlon.js" },
+ { Value, "latlon_infile", "/var/run/gps.txt" },
+ { Value, "sighup_pid_file", "/var/run/dnsmasq.pid" },
+ { Value, "name_change_script", "/usr/local/bin/announce_new_hosts.sh" },
+ { DynamicList, "service", "http://me.olsr:80|tcp|my little homepage" },
+ { Value, "services_file", "/var/run/services_olsr" },
+ { Value, "services_change_script", "/usr/local/bin/announce_new_services.sh" },
+ { DynamicList, "mac", "xx:xx:xx:xx:xx:xx[,0-255]" },
+ { Value, "macs_file", "/path/to/macs_file" },
+ { Value, "macs_change_script", "/path/to/script" }
+ },
+
+ ["olsrd_quagga.so.0.2.2"] = {
+ { StaticList, "redistribute", {
+ "system", "kernel", "connect", "static", "rip", "ripng", "ospf",
+ "ospf6", "isis", "bgp", "hsls"
+ } },
+ { ListValue, "ExportRoutes", { "only", "both" } },
+ { Flag, "LocalPref", "true" },
+ { Value, "Distance", Range(0,255) }
+ },
+
+ ["olsrd_secure.so.0.5"] = {
+ { Value, "Keyfile", "/etc/private-olsr.key" }
+ },
+
+ ["olsrd_txtinfo.so.0.1"] = {
+ { Value, "accept", "127.0.0.1" }
+ },
+
+ ["olsrd_jsoninfo.so.0.0"] = {
+ { Value, "accept", "127.0.0.1" },
+ { Value, "port", "9090" },
+ { Value, "UUIDFile", "/etc/olsrd/olsrd.uuid" },
+
+ },
+
+ ["olsrd_watchdog.so.0.1"] = {
+ { Value, "file", "/var/run/olsrd.watchdog" },
+ { Value, "interval", "30" }
+ },
+
+ ["olsrd_mdns.so.1.0.0"] = {
+ { DynamicList, "NonOlsrIf", "lan" }
+ },
+
+ ["olsrd_p2pd.so.0.1.0"] = {
+ { DynamicList, "NonOlsrIf", "lan" },
+ { Value, "P2pdTtl", "10" }
+ },
+
+ ["olsrd_arprefresh.so.0.1"] = {},
+ ["olsrd_dot_draw.so.0.3"] = {},
+ ["olsrd_dyn_gw_plain.so.0.4"] = {},
+ ["olsrd_pgraph.so.1.1"] = {},
+ ["olsrd_tas.so.0.1"] = {}
+ }
+
+
+ -- build plugin options with dependencies
+ if knownPlParams[arg[1]] then
+ for _, option in ipairs(knownPlParams[arg[1]]) do
+ local otype, name, default, uci2cbi, cbi2uci = unpack(option)
+ local values
+
+ if type(default) == "table" then
+ values = default
+ default = default[1]
+ end
+
+ if otype == Flag then
+ local bool = p:option( Flag, name, name )
+ if default == "yes" or default == "no" then
+ bool.enabled = "yes"
+ bool.disabled = "no"
+ elseif default == "on" or default == "off" then
+ bool.enabled = "on"
+ bool.disabled = "off"
+ elseif default == "1" or default == "0" then
+ bool.enabled = "1"
+ bool.disabled = "0"
+ else
+ bool.enabled = "true"
+ bool.disabled = "false"
+ end
+ bool.optional = true
+ bool.default = default
+ bool:depends({ library = plugin })
+ else
+ local field = p:option( otype, name, name )
+ if values then
+ for _, value in ipairs(values) do
+ field:value( value )
+ end
+ end
+ if type(uci2cbi) == "function" then
+ function field.cfgvalue(self, section)
+ return uci2cbi(otype.cfgvalue(self, section))
+ end
+ end
+ if type(cbi2uci) == "function" then
+ function field.formvalue(self, section)
+ return cbi2uci(otype.formvalue(self, section))
+ end
+ end
+ field.optional = true
+ field.default = default
+ --field:depends({ library = arg[1] })
+ end
+ end
+ end
+
+ return mp
+
+else
+
+ mpi = Map("olsrd", translate("OLSR - Plugins"))
+
+ local plugins = {}
+ mpi.uci:foreach("olsrd", "LoadPlugin",
+ function(section)
+ if section.library and not plugins[section.library] then
+ plugins[section.library] = true
+ end
+ end
+ )
+
+ -- create a loadplugin section for each found plugin
+ for v in fs.dir("/usr/lib") do
+ if v:sub(1, 6) == "olsrd_" then
+ if not plugins[v] then
+ mpi.uci:section(
+ "olsrd", "LoadPlugin", nil,
+ { library = v, ignore = 1 }
+ )
+ end
+ end
+ end
+
+ t = mpi:section( TypedSection, "LoadPlugin", translate("Plugins") )
+ t.anonymous = true
+ t.template = "cbi/tblsection"
+ t.override_scheme = true
+ function t.extedit(self, section)
+ local lib = self.map:get(section, "library") or ""
+ return luci.dispatcher.build_url("admin", "services", "olsrd", "plugins") .. "/" .. lib
+ end
+
+ ign = t:option( Flag, "ignore", translate("Enabled") )
+ ign.enabled = "0"
+ ign.disabled = "1"
+ ign.rmempty = false
+ function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+ end
+
+ t:option( DummyValue, "library", translate("Library") )
+
+ return mpi
+end
diff --git a/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins6.lua b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins6.lua
new file mode 100644
index 000000000..221938e7a
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/model/cbi/olsr/olsrdplugins6.lua
@@ -0,0 +1,270 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local ip = require "luci.ip"
+local fs = require "nixio.fs"
+
+if arg[1] then
+ mp = Map("olsrd6", translate("OLSR - Plugins"))
+
+ p = mp:section(TypedSection, "LoadPlugin", translate("Plugin configuration"))
+ p:depends("library", arg[1])
+ p.anonymous = true
+
+ ign = p:option(Flag, "ignore", translate("Enable"))
+ ign.enabled = "0"
+ ign.disabled = "1"
+ ign.rmempty = false
+ function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+ end
+
+ lib = p:option(DummyValue, "library", translate("Library"))
+ lib.default = arg[1]
+
+ local function Range(x,y)
+ local t = {}
+ for i = x, y do t[#t+1] = i end
+ return t
+ end
+
+ local function Cidr2IpMask(val)
+ if val then
+ for i = 1, #val do
+ local cidr = ip.IPv4(val[i]) or ip.IPv6(val[i])
+ if cidr then
+ val[i] = cidr:network():string() .. " " .. cidr:mask():string()
+ end
+ end
+ return val
+ end
+ end
+
+ local function IpMask2Cidr(val)
+ if val then
+ for i = 1, #val do
+ local ip, mask = val[i]:gmatch("([^%s]+)%s+([^%s]+)")()
+ local cidr
+ if ip and mask and ip:match(":") then
+ cidr = ip.IPv6(ip, mask)
+ elseif ip and mask then
+ cidr = ip.IPv4(ip, mask)
+ end
+
+ if cidr then
+ val[i] = cidr:string()
+ end
+ end
+ return val
+ end
+ end
+
+
+ local knownPlParams = {
+ ["olsrd_bmf.so.1.5.3"] = {
+ { Value, "BmfInterface", "bmf0" },
+ { Value, "BmfInterfaceIp", "10.10.10.234/24" },
+ { Flag, "DoLocalBroadcast", "no" },
+ { Flag, "CapturePacketsOnOlsrInterfaces", "yes" },
+ { ListValue, "BmfMechanism", { "UnicastPromiscuous", "Broadcast" } },
+ { Value, "BroadcastRetransmitCount", "2" },
+ { Value, "FanOutLimit", "4" },
+ { DynamicList, "NonOlsrIf", "br-lan" }
+ },
+
+ ["olsrd_dyn_gw.so.0.4"] = {
+ { Value, "Interval", "40" },
+ { DynamicList, "Ping", "141.1.1.1" },
+ { DynamicList, "HNA", "192.168.80.0/24", IpMask2Cidr, Cidr2IpMask }
+ },
+
+ ["olsrd_httpinfo.so.0.1"] = {
+ { Value, "port", "80" },
+ { DynamicList, "Host", "163.24.87.3" },
+ { DynamicList, "Net", "0.0.0.0/0", Cidr2IpMask }
+ },
+
+ ["olsrd_nameservice.so.0.3"] = {
+ { DynamicList, "name", "my-name.mesh" },
+ { DynamicList, "hosts", "1.2.3.4 name-for-other-interface.mesh" },
+ { Value, "suffix", ".olsr" },
+ { Value, "hosts_file", "/path/to/hosts_file" },
+ { Value, "add_hosts", "/path/to/file" },
+ { Value, "dns_server", "141.1.1.1" },
+ { Value, "resolv_file", "/path/to/resolv.conf" },
+ { Value, "interval", "120" },
+ { Value, "timeout", "240" },
+ { Value, "lat", "12.123" },
+ { Value, "lon", "12.123" },
+ { Value, "latlon_file", "/var/run/latlon.js.ipv6" },
+ { Value, "latlon_infile", "/var/run/gps.txt" },
+ { Value, "sighup_pid_file", "/var/run/dnsmasq.pid" },
+ { Value, "name_change_script", "/usr/local/bin/announce_new_hosts.sh" },
+ { DynamicList, "service", "http://me.olsr:80|tcp|my little homepage" },
+ { Value, "services_file", "/var/run/services_olsr" },
+ { Value, "services_change_script", "/usr/local/bin/announce_new_services.sh" },
+ { DynamicList, "mac", "xx:xx:xx:xx:xx:xx[,0-255]" },
+ { Value, "macs_file", "/path/to/macs_file" },
+ { Value, "macs_change_script", "/path/to/script" }
+ },
+
+ ["olsrd_quagga.so.0.2.2"] = {
+ { StaticList, "redistribute", {
+ "system", "kernel", "connect", "static", "rip", "ripng", "ospf",
+ "ospf6", "isis", "bgp", "hsls"
+ } },
+ { ListValue, "ExportRoutes", { "only", "both" } },
+ { Flag, "LocalPref", "true" },
+ { Value, "Distance", Range(0,255) }
+ },
+
+ ["olsrd_secure.so.0.5"] = {
+ { Value, "Keyfile", "/etc/private-olsr.key" }
+ },
+
+ ["olsrd_txtinfo.so.0.1"] = {
+ { Value, "accept", "::1/128" }
+ },
+
+ ["olsrd_jsoninfo.so.0.0"] = {
+ { Value, "accept", "::1/128" },
+ { Value, "port", "9090" },
+ { Value, "UUIDFile", "/etc/olsrd/olsrd.uuid.ipv6" },
+
+ },
+
+ ["olsrd_watchdog.so.0.1"] = {
+ { Value, "file", "/var/run/olsrd.watchdog.ipv6" },
+ { Value, "interval", "30" }
+ },
+
+ ["olsrd_mdns.so.1.0.0"] = {
+ { DynamicList, "NonOlsrIf", "lan" }
+ },
+
+ ["olsrd_p2pd.so.0.1.0"] = {
+ { DynamicList, "NonOlsrIf", "lan" },
+ { Value, "P2pdTtl", "10" }
+ },
+
+ ["olsrd_arprefresh.so.0.1"] = {},
+ ["olsrd_dot_draw.so.0.3"] = {},
+ ["olsrd_dyn_gw_plain.so.0.4"] = {},
+ ["olsrd_pgraph.so.1.1"] = {},
+ ["olsrd_tas.so.0.1"] = {}
+ }
+
+
+ -- build plugin options with dependencies
+ if knownPlParams[arg[1]] then
+ for _, option in ipairs(knownPlParams[arg[1]]) do
+ local otype, name, default, uci2cbi, cbi2uci = unpack(option)
+ local values
+
+ if type(default) == "table" then
+ values = default
+ default = default[1]
+ end
+
+ if otype == Flag then
+ local bool = p:option( Flag, name, name )
+ if default == "yes" or default == "no" then
+ bool.enabled = "yes"
+ bool.disabled = "no"
+ elseif default == "on" or default == "off" then
+ bool.enabled = "on"
+ bool.disabled = "off"
+ elseif default == "1" or default == "0" then
+ bool.enabled = "1"
+ bool.disabled = "0"
+ else
+ bool.enabled = "true"
+ bool.disabled = "false"
+ end
+ bool.optional = true
+ bool.default = default
+ bool:depends({ library = plugin })
+ else
+ local field = p:option( otype, name, name )
+ if values then
+ for _, value in ipairs(values) do
+ field:value( value )
+ end
+ end
+ if type(uci2cbi) == "function" then
+ function field.cfgvalue(self, section)
+ return uci2cbi(otype.cfgvalue(self, section))
+ end
+ end
+ if type(cbi2uci) == "function" then
+ function field.formvalue(self, section)
+ return cbi2uci(otype.formvalue(self, section))
+ end
+ end
+ field.optional = true
+ field.default = default
+ --field:depends({ library = arg[1] })
+ end
+ end
+ end
+
+ return mp
+
+else
+
+ mpi = Map("olsrd6", translate("OLSR - Plugins"))
+
+ local plugins = {}
+ mpi.uci:foreach("olsrd6", "LoadPlugin",
+ function(section)
+ if section.library and not plugins[section.library] then
+ plugins[section.library] = true
+ end
+ end
+ )
+
+ -- create a loadplugin section for each found plugin
+ for v in fs.dir("/usr/lib") do
+ if v:sub(1, 6) == "olsrd_" then
+ if not plugins[v] then
+ mpi.uci:section(
+ "olsrd6", "LoadPlugin", nil,
+ { library = v, ignore = 1 }
+ )
+ end
+ end
+ end
+
+ t = mpi:section( TypedSection, "LoadPlugin", translate("Plugins") )
+ t.anonymous = true
+ t.template = "cbi/tblsection"
+ t.override_scheme = true
+ function t.extedit(self, section)
+ local lib = self.map:get(section, "library") or ""
+ return luci.dispatcher.build_url("admin", "services", "olsrd6", "plugins") .. "/" .. lib
+ end
+
+ ign = t:option( Flag, "ignore", translate("Enabled") )
+ ign.enabled = "0"
+ ign.disabled = "1"
+ ign.rmempty = false
+ function ign.cfgvalue(self, section)
+ return Flag.cfgvalue(self, section) or "0"
+ end
+
+ t:option( DummyValue, "library", translate("Library") )
+
+ return mpi
+end
diff --git a/applications/luci-app-olsr/luasrc/tools/olsr.lua b/applications/luci-app-olsr/luasrc/tools/olsr.lua
new file mode 100644
index 000000000..dfd8262f0
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/tools/olsr.lua
@@ -0,0 +1,42 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+]]--
+
+module("luci.tools.olsr", package.seeall)
+
+function etx_color(etx)
+ local color = "#bb3333"
+ if etx == 0 then
+ color = "#bb3333"
+ elseif etx < 2 then
+ color = "#00cc00"
+ elseif etx < 4 then
+ color = "#ffcb05"
+ elseif etx < 10 then
+ color = "#ff6600"
+ end
+ return color
+end
+
+function snr_color(snr)
+ local color = "#bb3333"
+ if snr == 0 then
+ color = "#bb3333"
+ elseif snr > 30 then
+ color = "#00cc00"
+ elseif snr > 20 then
+ color = "#ffcb05"
+ elseif snr > 5 then
+ color = "#ff6600"
+ end
+ return color
+end
+
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/common_js.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/common_js.htm
new file mode 100644
index 000000000..1ee763e11
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/common_js.htm
@@ -0,0 +1,35 @@
+<% if has_v4 and has_v6 then %>
+<script type="text/javascript">//<![CDATA[
+
+function css(selector, property, value) {
+ for (var i=0; i<document.styleSheets.length;i++) {
+ try { document.styleSheets[i].insertRule(selector+ ' {'+property+':'+value+'}', document.styleSheets[i].cssRules.length);
+ } catch(err) {try { document.styleSheets[i].addRule(selector, property+':'+value);} catch(err) {}}//IE
+ }
+}
+
+window.onload = function() {
+ buttons = '<input type="button" name="show-proto-4" id="show-proto-4" class="cbi-button cbi-button-apply" style="margin-right: 5px" value="<%:Hide IPv4%>">'
+ buttons += '<input type="button" name="show-proto-6" id="show-proto-6" class="cbi-button cbi-button-apply" value="<%:Hide IPv6%>">'
+
+ document.getElementById('togglebuttons').innerHTML = buttons;
+
+ var visible = true;
+ document.getElementById('show-proto-4').onclick = function() {
+ visible = !visible;
+ document.getElementById('show-proto-4').value = visible ? '<%:Hide IPv4%>' : '<%:Show IPv4%>';
+ document.getElementById('show-proto-4').className = visible ? 'cbi-button cbi-button-apply' : 'cbi-button cbi-button-reset';
+ css('.proto-4', 'display', visible ? 'table-row' : 'none')
+ };
+
+ var visible6 = true;
+ document.getElementById('show-proto-6').onclick = function() {
+ visible6 = !visible6;
+ document.getElementById('show-proto-6').value = visible6 ? '<%:Hide IPv6%>' : '<%:Show IPv6%>';
+ document.getElementById('show-proto-6').className = visible6 ? 'cbi-button cbi-button-apply' : 'cbi-button cbi-button-reset';
+ css('.proto-6', 'display', visible6 ? 'table-row' : 'none')
+ };
+
+}
+//]]></script>
+<%end %>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/error_olsr.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/error_olsr.htm
new file mode 100644
index 000000000..2c872fa5a
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/error_olsr.htm
@@ -0,0 +1,17 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+-%>
+<%+header%>
+<h2><a id="content" name="content"><%:OLSR Daemon%></a></h2>
+<p class="error"><%:Unable to connect to the OLSR daemon!%></p>
+<p><%:Make sure that OLSRd is running, the "jsoninfo" plugin is loaded, configured on port 9090 and accepts connections from "127.0.0.1".%></p>
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/hna.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/hna.htm
new file mode 100644
index 000000000..689bafdfa
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/hna.htm
@@ -0,0 +1,129 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+-%>
+
+<%
+local i = 1
+
+if luci.http.formvalue("status") == "1" then
+ local rv = {}
+ for k, hna in ipairs(hna) do
+ rv[#rv+1] = {
+ proto = hna["proto"],
+ destination = hna["destination"],
+ genmask = hna["genmask"],
+ gateway = hna["gateway"],
+ hostname = hna["hostname"],
+ validityTime = hna["validityTime"]
+ }
+ end
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(rv)
+ return
+end
+%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+<script type="text/javascript">//<![CDATA[
+XHR.poll(10, '<%=REQUEST_URI%>', { status: 1 },
+ function(x, info)
+ {
+ var hnadiv = document.getElementById('olsrd_hna');
+ if (hnadiv)
+ {
+ var s = '';
+ for (var idx = 0; idx < info.length; idx++)
+ {
+ var hna = info[idx];
+ var linkgw = ''
+ s += '<tr class="cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-' + hna.proto + '">'
+ if (hna.proto == '6') {
+ linkgw = '<a href="http://[' + hna.gateway + ']/cgi-bin-status.html">' + hna.gateway + '</a>'
+ } else {
+ linkgw = '<a href="http://' + hna.gateway + '/cgi-bin-status.html">' + hna.gateway + '</a>'
+ }
+
+ if (hna.validityTime != undefined) {
+ validity = hna.validityTime + 's'
+ } else {
+ validity = '-'
+ }
+
+ if (hna.hostname != undefined) {
+ hostname = ' / <a href="http://' + hna.hostname + '/cgi-bin-status.html">' + hna.hostname + '</a>'
+ } else {
+ hostname = ''
+ }
+
+ s += String.format(
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>', hna.destination + '/' + hna.genmask, linkgw + hostname, validity
+ )
+ s += '</tr>'
+ }
+ hnadiv.innerHTML = s;
+ }
+}
+);
+//]]></script>
+
+<h2><a id="content" name="content"><%:Active host net announcements%></a></h2>
+
+<div id="togglebuttons"></div>
+<fieldset class="cbi-section">
+
+ <legend><%:Overview of currently active OLSR host net announcements%></legend>
+ <table class="cbi-section-table">
+ <thead>
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:Announced network%></th>
+ <th class="cbi-section-table-cell"><%:OLSR gateway%></th>
+ <th class="cbi-section-table-cell"><%:Validity Time%></th>
+ </tr>
+
+ </thead>
+ <tbody id="olsrd_hna">
+ <% for k, route in ipairs(hna) do %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=hna[k].proto%>">
+ <td class="cbi-section-table-cell"><%=hna[k].destination%>/<%=hna[k].genmask%> </td>
+ <td class="cbi-section-table-cell">
+ <% if hna[k].proto == '6' then %>
+ <a href="http://[<%=hna[k].gateway%>]/cgi-bin-status.html"><%=hna[k].gateway%></a>
+ <% else %>
+ <a href="http://<%=hna[k].gateway%>/cgi-bin-status.html"><%=hna[k].gateway%></a>
+ <% end %>
+ <% if hna[k].hostname then %>
+ / <a href="http://<%=hna[k].hostname%>/cgi-bin-status.html"><%=hna[k].hostname%></a>
+ <% end %>
+ </td>
+ <% if hna[k].validityTime then
+ validity = hna[k].validityTime .. 's'
+ else
+ validity = '-'
+ end %>
+
+ <td class="cbi-section-table-cell"><%=validity%></td>
+ </tr>
+
+ <% i = ((i % 2) + 1)
+ end %>
+ </tbody>
+ </table>
+</fieldset>
+
+<%+status-olsr/common_js%>
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/interfaces.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/interfaces.htm
new file mode 100644
index 000000000..dd1a21ea6
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/interfaces.htm
@@ -0,0 +1,57 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+-%>
+
+<%
+local i = 1
+%>
+
+<%+header%>
+
+<h2><a id="content" name="content"><%:Interfaces%></a></h2>
+
+<div id="togglebuttons"></div>
+
+<fieldset class="cbi-section">
+ <legend><%:Overview of interfaces where OLSR is running%></legend>
+
+ <table class="cbi-section-table">
+ <tr>
+ <th class="cbi-section-table-cell"><%:Interface%></th>
+ <th class="cbi-section-table-cell"><%:State%></th>
+ <th class="cbi-section-table-cell"><%:MTU%></th>
+ <th class="cbi-section-table-cell"><%:WLAN%></th>
+ <th class="cbi-section-table-cell"><%:Source address%></th>
+ <th class="cbi-section-table-cell"><%:Netmask%></th>
+ <th class="cbi-section-table-cell"><%:Broadcast address%></th>
+ </tr>
+
+ <% for k, iface in ipairs(iface) do %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=iface.proto%>">
+ <td class="cbi-section-table-cell"><%=iface.name%></td>
+ <td class="cbi-section-table-cell"><%=iface.state%></td>
+ <td class="cbi-section-table-cell"><%=iface.olsrMTU%></td>
+ <td class="cbi-section-table-cell"><%=iface.wireless and luci.i18n.translate('yes') or luci.i18n.translate('no')%></td>
+ <td class="cbi-section-table-cell"><%=iface.ipv4Address or iface.ipv6Address%></td>
+ <td class="cbi-section-table-cell"><%=iface.netmask%></td>
+ <td class="cbi-section-table-cell"><%=iface.broadcast or iface.multicast%></td>
+ </tr>
+ <% i = ((i % 2) + 1)
+ end %>
+ </table>
+</fieldset>
+<%+status-olsr/common_js%>
+<%+footer%>
+
+
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/legend.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/legend.htm
new file mode 100644
index 000000000..2f598489d
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/legend.htm
@@ -0,0 +1,24 @@
+<h3><%:Legend%>:</h3>
+<ul>
+ <li><strong>LQ: </strong><%:Success rate of packages received from the neighbour%></li>
+ <li><strong>NLQ: </strong><%:Success rate of packages sent to the neighbour%></li>
+ <li><strong>ETX: </strong><%:Expected retransmission count%></li>
+ <li style="list-style: none">
+ <ul>
+ <li><strong><span style="color:#00cc00"><%:Green%></span></strong>:<%:Very good (ETX < 2)%></li>
+ <li><strong><span style="color:#ffcb05"><%:Yellow%></span></strong>:<%:Good (2 < ETX < 4)%></li>
+ <li><strong><span style="color:#ff6600"><%:Orange%></span></strong>:<%:Still usable (4 < ETX < 10)%></li>
+ <li><strong><span style="color:#bb3333"><%:Red%></span></strong>:<%:Bad (ETX > 10)%></li>
+ </ul>
+ </li>
+ <li><strong>SNR: </strong><%:Signal Noise Ratio in dB%></li>
+ <li style="list-style: none">
+ <ul>
+ <li><strong><span style="color:#00cc00"><%:Green%></span></strong>:<%:Very good (SNR > 30)%></li>
+ <li><strong><span style="color:#ffcb05"><%:Yellow%></span></strong>:<%:Good (30 > SNR > 20)%></li>
+ <li><strong><span style="color:#ff6600"><%:Orange%></span></strong>:<%:Still usable (20 > SNR > 5)%></li>
+ <li><strong><span style="color:#bb3333"><%:Red%></span></strong>:<%:Bad (SNR < 5)%></li>
+ </ul>
+ </li>
+</ul>
+
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/mid.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/mid.htm
new file mode 100644
index 000000000..ec5caaa95
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/mid.htm
@@ -0,0 +1,58 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
+-%>
+<%
+local i = 1
+%>
+
+<%+header%>
+<h2><a id="content" name="content"><%:Active MID announcements%></a></h2>
+
+<div id="togglebuttons"></div>
+<fieldset class="cbi-section">
+ <legend><%:Overview of known multiple interface announcements%></legend>
+ <table class="cbi-section-table">
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:OLSR node%></th>
+ <th class="cbi-section-table-cell" ><%:Secondary OLSR interfaces%></th>
+ </tr>
+
+ <% for k, mid in ipairs(mids) do
+ local aliases = ''
+ for k,v in ipairs(mid.aliases) do
+ if aliases == '' then
+ sep = ''
+ else
+ sep = ', '
+ end
+ aliases = v.ipAddress .. sep .. aliases
+ end
+ local host = mid.ipAddress
+ if mid.proto == '6' then
+ host = '[' .. mid.ipAddress .. ']'
+ end
+ %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=mid.proto%>">
+ <td class="cbi-section-table-cell"><a href="http://<%=host%>/cgi-bin-status.html"><%=mid.ipAddress%></a></td>
+ <td class="cbi-section-table-cell"><%=aliases%></td>
+ </tr>
+
+ <% i = ((i % 2) + 1)
+ end %>
+ </table>
+</fieldset>
+<%+status-olsr/common_js%>
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/neighbors.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/neighbors.htm
new file mode 100644
index 000000000..daa52831f
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/neighbors.htm
@@ -0,0 +1,181 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+-%>
+
+<%
+local olsrtools = require "luci.tools.olsr"
+local i = 1
+
+if luci.http.formvalue("status") == "1" then
+ local rv = {}
+ for k, link in ipairs(links) do
+ link.linkCost = tonumber(link.linkCost)/1024 or 0
+ if link.linkCost == 4096 then
+ link.linkCost = 0
+ end
+ local color = olsrtools.etx_color(link.linkCost)
+ local snr_color = olsrtools.snr_color(link.snr)
+ defaultgw_color = ""
+ if link.defaultgw == 1 then
+ defaultgw_color = "#ffff99"
+ end
+
+ rv[#rv+1] = {
+ rip = link.remoteIP,
+ hn = link.hostname,
+ lip = link.localIP,
+ ifn = link.interface,
+ lq = string.format("%.3f", link.linkQuality),
+ nlq = string.format("%.3f",link.neighborLinkQuality),
+ cost = string.format("%.3f", link.linkCost),
+ snr = link.snr,
+ signal = link.signal,
+ noise = link.noise,
+ color = color,
+ snr_color = snr_color,
+ dfgcolor = defaultgw_color,
+ proto = link.proto
+ }
+ end
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(rv)
+ return
+end
+%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+<script type="text/javascript">//<![CDATA[
+
+ XHR.poll(10 , '<%=REQUEST_URI%>', { status: 1 },
+ function(x, info)
+ {
+ var nt = document.getElementById('olsr_neigh_table');
+ if (nt)
+ {
+ var s = '';
+ for (var idx = 0; idx < info.length; idx++)
+ {
+ var neigh = info[idx];
+
+ if (neigh.proto == '6') {
+ s += String.format(
+ '<tr class="cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-%s">' +
+ '<td class="cbi-section-table-titles" style="background-color:%s"><a href="http://[%s]/cgi-bin-status.html">%s</a></td>',
+ neigh.proto, neigh.dfgcolor, neigh.rip, neigh.rip
+ );
+ } else {
+ s += String.format(
+ '<tr class="cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-%s">' +
+ '<td class="cbi-section-table-titles" style="background-color:%s"><a href="http://%s/cgi-bin-status.html">%s</a></td>',
+ neigh.proto, neigh.dfgcolor, neigh.rip, neigh.rip
+ );
+ }
+ if (neigh.hn) {
+ s += String.format(
+ '<td class="cbi-section-table-titles" style="background-color:%s"><a href="http://%s/cgi-bin-status.html">%s</a></td>',
+ neigh.dfgcolor, neigh.hn, neigh.hn
+ );
+ } else {
+ s += String.format(
+ '<td class="cbi-section-table-titles" style="background-color:%s">?</td>',
+ neigh.dfgcolor
+ );
+ }
+ s += String.format(
+ '<td class="cbi-section-table-titles" style="background-color:%s">%s</td>' +
+ '<td class="cbi-section-table-titles" style="background-color:%s">%s</td>' +
+ '<td class="cbi-section-table-titles" style="background-color:%s">%s</td>' +
+ '<td class="cbi-section-table-titles" style="background-color:%s">%s</td>' +
+ '<td class="cbi-section-table-titles" style="background-color:%s">%s</td>' +
+ '<td class="cbi-section-table-titles" style="background-color:%s" title="Signal: %s Noise: %s">%s</td>' +
+ '</tr>',
+ neigh.dfgcolor, neigh.ifn, neigh.dfgcolor, neigh.lip, neigh.dfgcolor, neigh.lq, neigh.dfgcolor, neigh.nlq, neigh.color, neigh.cost, neigh.snr_color, neigh.signal, neigh.noise, neigh.snr || '?'
+ );
+ }
+
+ nt.innerHTML = s;
+ }
+ }
+ );
+//]]></script>
+
+
+<h2><a id="content" name="content"><%:OLSR connections%></a></h2>
+
+<div id="togglebuttons"></div>
+
+<fieldset class="cbi-section">
+ <legend><%:Overview of currently established OLSR connections%></legend>
+
+ <table class="cbi-section-table">
+ <thead>
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:Neighbour IP%></th>
+ <th class="cbi-section-table-cell"><%:Hostname%></th>
+ <th class="cbi-section-table-cell"><%:Interface%></th>
+ <th class="cbi-section-table-cell"><%:Local interface IP%></th>
+ <th class="cbi-section-table-cell">LQ</th>
+ <th class="cbi-section-table-cell">NLQ</th>
+ <th class="cbi-section-table-cell">ETX</th>
+ <th class="cbi-section-table-cell">SNR</th>
+ </tr>
+ </thead>
+
+ <tbody id="olsr_neigh_table">
+ <% local i = 1
+ for k, link in ipairs(links) do
+ link.linkCost = tonumber(link.linkCost)/1024 or 0
+ if link.linkCost == 4096 then
+ link.linkCost = 0
+ end
+
+ color = olsrtools.etx_color(link.linkCost)
+ snr_color = olsrtools.snr_color(link.snr)
+
+ if link.snr == 0 then
+ link.snr = '?'
+ end
+
+ defaultgw_color = ""
+ if link.defaultgw == 1 then
+ defaultgw_color = "#ffff99"
+ end
+ %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=link.proto%>">
+ <% if link.proto == "6" then %>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><a href="http://[<%=link.remoteIP%>]/cgi-bin-status.html"><%=link.remoteIP%></a></td>
+ <% else %>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><a href="http://<%=link.remoteIP%>/cgi-bin-status.html"><%=link.remoteIP%></a></td>
+ <% end %>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><a href="http://<%=link.hostname%>/cgi-bin-status.html"><%=link.hostname%></a></td>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><%=link.interface%></td>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><%=link.localIP%></td>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><%=string.format("%.3f", link.linkQuality)%></td>
+ <td class="cbi-section-table-titles" style="background-color:<%=defaultgw_color%>"><%=string.format("%.3f", link.neighborLinkQuality)%></td>
+ <td class="cbi-section-table-titles" style="background-color:<%=color%>"><%=string.format("%.3f", link.linkCost)%></td>
+ <td class="cbi-section-table-titles" style="background-color:<%=snr_color%>" title="Signal: <%=link.signal%> Noise: <%=link.noise%>"><%=link.snr%></td>
+ </tr>
+ <%
+ i = ((i % 2) + 1)
+ end %>
+ </tbody>
+ </table>
+<br />
+
+<%+status-olsr/legend%>
+</fieldset>
+<%+status-olsr/common_js%>
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/overview.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/overview.htm
new file mode 100644
index 000000000..6d8eca874
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/overview.htm
@@ -0,0 +1,220 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+-%>
+
+<%
+local ipv = luci.model.uci.cursor():get_first("olsrd", "olsrd", "IpVersion", "4")
+
+function write_conf(conf, file)
+ local fs = require "luci.fs"
+ if fs.access(conf) then
+ luci.http.header("Content-Disposition", "attachment; filename="..file)
+ luci.http.prepare_content("text/plain")
+ luci.http.write(fs.readfile(conf))
+ end
+end
+
+conf = luci.http.formvalue()
+
+if conf.openwrt then
+ write_conf("/etc/config/olsrd", "olsrd")
+ return false
+end
+
+if conf.conf_v4 then
+ write_conf("/var/etc/olsrd.conf.ipv4", "olsrd.conf.ipv4")
+ return false
+end
+
+if conf.conf_v6 then
+ write_conf("/var/etc/olsrd.conf.ipv6", "olsrd.conf.ipv6")
+ return false
+end
+
+if conf.conf then
+ write_conf("/var/etc/olsrd.conf", "olsrd.conf")
+ return false
+end
+
+%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+<script type="text/javascript">//<![CDATA[
+
+XHR.poll(10, '<%=REQUEST_URI%>/json', { },
+ function(x, info)
+ {
+ var e;
+
+ if (! info) {
+ document.getElementById('error').innerHTML = '<%:Could not get any data. Make sure the jsoninfo plugin is installed and allows connections from localhost.%>';
+ return
+ }
+ document.getElementById('error').innerHTML = '';
+
+ if (e = document.getElementById('version'))
+ var version;
+ var date;
+ if (info.v4.config.olsrdVersion != undefined) {
+ version = info.v4.config.olsrdVersion
+ date = info.v4.config.olsrdBuildDate
+ } else if (info.v6.config.olsrdVersion != undefined) {
+ version = info.v6.config.olsrdVersion
+ date = info.v6.config.olsrdBuildDate
+ } else {
+ version = 'unknown'
+ date = 'unknown'
+ }
+ e.innerHTML = version + '<br />' + date;
+
+ if (e = document.getElementById('nr_neigh'))
+ var neigh = 0;
+ if (info.v4.links != undefined) {
+ neigh = neigh + info.v4.links.length
+ }
+ if (info.v6.links != undefined) {
+ neigh = neigh + info.v6.links.length
+ }
+ e.innerHTML = neigh;
+
+
+ if (e = document.getElementById('nr_hna'))
+ var hna = 0;
+ if (info.v4.hna != undefined) {
+ hna = hna + info.v4.hna.length
+ }
+ if (info.v6.hna != undefined) {
+ hna = hna + info.v6.hna.length
+ }
+ e.innerHTML = hna;
+
+
+ if (e = document.getElementById('nr_ifaces'))
+ var nrint = 0
+ if (info.v4.interfaces != undefined) {
+ nrint = nrint + info.v4.interfaces.length
+ }
+ if (info.v6.interfaces != undefined) {
+ nrint = nrint + info.v6.interfaces.length
+ }
+ e.innerHTML = nrint
+
+
+ if (e = document.getElementById('nr_topo'))
+ var topo = 0;
+ var nodes = [];
+
+ Array.prototype.contains = function (element) {
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] == element) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (info.v4.topology != undefined) {
+ topo = topo + info.v4.topology.length;
+ for (var i = 0; i < info.v4.topology.length; i++) {
+ var destip = info.v4.topology[i].destinationIP
+ if (! nodes.contains(destip) ) {
+ nodes.push(destip)
+ }
+ }
+ }
+
+ if (info.v6.topology != undefined) {
+ topo = topo + info.v6.topology.length
+ for (var i = 0; i < info.v6.topology.length; i++) {
+ var destip = info.v6.topology[i].destinationIP
+ if (! nodes.contains(destip) ) {
+ nodes.push(destip)
+ }
+ }
+
+ }
+ e.innerHTML = topo;
+
+ if (e = document.getElementById('nr_nodes'))
+ e.innerHTML = nodes.length;
+
+ if (e = document.getElementById('meshfactor'))
+ var meshfactor = topo / nodes.length
+ e.innerHTML = meshfactor.toFixed(2)
+ }
+ );
+//]]></script>
+
+
+<div id="error" class="error"></div>
+
+<h2><a id="content" name="content">OLSR <%:Overview%></a></h2>
+
+<fieldset class="cbi-section">
+ <legend><%:Network%></legend>
+
+ <table width="100%" cellspacing="10">
+ <tr><td width="33%"><%:Interfaces%></td><td>
+ <a href="<%=REQUEST_URI%>/interfaces">
+ <span id="nr_ifaces">-<span>
+ </a>
+ </td></tr>
+ <tr><td width="33%"><%:Neighbors%></td><td>
+ <a href="<%=REQUEST_URI%>/neighbors">
+ <span id="nr_neigh">-</span>
+ </a>
+ </td></tr>
+ <tr><td width="33%"><%:Nodes%></td><td>
+ <a href="<%=REQUEST_URI%>/topology">
+ <span id="nr_nodes">-</span>
+ </a>
+ </td></tr>
+ <tr><td width="33%"><%:HNA%></td><td>
+ <a href="<%=REQUEST_URI%>/hna">
+ <span id="nr_hna">-</span>
+ </a>
+ </td></tr>
+ <tr><td width="33%"><%:Links total%></td><td>
+ <a href="<%=REQUEST_URI%>/topology">
+ <span id="nr_topo">-</span>
+ </a>
+ </td></tr>
+ <tr><td width="33%"><%:Links per node (average)%></td><td>
+ <span id="meshfactor">-</span>
+ </td></tr>
+
+
+ </table>
+</fieldset>
+
+
+<fieldset class="cbi-section">
+ <legend>OLSR <%:Configuration%></legend>
+ <table width="100%" cellspacing="10">
+ <tr><td width="33%"><%:Version%></td><td>
+ <span id="version">-<span>
+ </td></tr>
+ <tr><td width="33%"><%:Download Config%></td><td>
+ <a href="<%=REQUEST_URI%>?openwrt">OpenWrt</a>,
+ <% if ipv == "6and4" then %>
+ <a href="<%=REQUEST_URI%>?conf_v4">OLSRD IPv4</a>,
+ <a href="<%=REQUEST_URI%>?conf_v6">OLSRD IPv6</a>
+ <% else %>
+ <a href="<%=REQUEST_URI%>?conf">OLSRD</a>
+ <% end %>
+ </td></tr>
+ </table>
+</fieldset>
+
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/routes.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/routes.htm
new file mode 100644
index 000000000..76e1b1078
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/routes.htm
@@ -0,0 +1,148 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+-%>
+
+<%
+
+local olsrtools = require "luci.tools.olsr"
+local i = 1
+
+if luci.http.formvalue("status") == "1" then
+ local rv = {}
+ for k, route in ipairs(routes) do
+ local ETX = string.format("%.3f", tonumber(route.rtpMetricCost)/1024 or 0)
+ rv[#rv+1] = {
+ hostname = route.hostname,
+ dest = route.destination,
+ genmask = route.genmask,
+ gw = route.gateway,
+ interface = route.networkInterface,
+ metric = route.metric,
+ etx = ETX,
+ color = olsrtools.etx_color(tonumber(ETX))
+ }
+ end
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(rv)
+ return
+end
+
+%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+<script type="text/javascript">//<![CDATA[
+
+XHR.poll(20, '<%=REQUEST_URI%>', { status: 1 },
+ function(x, info)
+ {
+
+ var rt = document.getElementById('olsrd_routes');
+ if (rt)
+ {
+ var s = '';
+ for (var idx = 0; idx < info.length; idx++)
+ {
+ var route = info[idx];
+
+ s += String.format(
+ '<tr class="cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-%s">' +
+ '<td class="cbi-section-table-cell">%s/%s</td>' +
+ '<td class="cbi-section-table-cell">' +
+ '<a href="http://%s/cgi-bin-status.html">%s</a>',
+ route.proto, route.dest, route.genmask, route.gw, route.gw
+ )
+
+ if (route.hostname) {
+ if (hna.proto == '6') {
+ s += String.format(
+ ' / <a href="http://[%s]/cgi-bin-status.html">%s</a>',
+ route.hostname, route.hostname || '?'
+ );
+ } else {
+ s += String.format(
+ ' / <a href="http://%s/cgi-bin-status.html">%s</a>',
+ route.hostname, route.hostname || '?'
+ );
+ }
+
+ }
+ s += String.format(
+ '</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell" style="background-color:%s">%s</td>' +
+ '</tr>',
+ route.interface, route.metric, route.color, route.etx || '?'
+ );
+ }
+ }
+ rt.innerHTML = s;
+
+ }
+ );
+//]]></script>
+
+
+
+<h2><a id="content" name="content"><%:Known OLSR routes%></a></h2>
+
+<div id="togglebuttons"></div>
+
+<fieldset class="cbi-section">
+<legend><%:Overview of currently known routes to other OLSR nodes%></legend>
+
+<table class="cbi-section-table">
+ <thead>
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:Announced network%></th>
+ <th class="cbi-section-table-cell"><%:OLSR gateway%></th>
+ <th class="cbi-section-table-cell"><%:Interface%></th>
+ <th class="cbi-section-table-cell"><%:Metric%></th>
+ <th class="cbi-section-table-cell">ETX</th>
+ </tr>
+ </thead>
+
+ <tbody id="olsrd_routes">
+
+ <% for k, route in ipairs(routes) do
+ ETX = tonumber(route.rtpMetricCost)/1024 or '0'
+ color = olsrtools.etx_color(ETX)
+ %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=route.proto%>">
+ <td class="cbi-section-table-cell"><%=route.destination%>/<%=route.genmask%></td>
+ <td class="cbi-section-table-cell">
+ <% if route.proto == '6' then %>
+ <a href="http://[<%=route.gateway%>]/cgi-bin-status.html"><%=route.gateway%></a>
+ <% else %>
+ <a href="http://<%=route.gateway%>/cgi-bin-status.html"><%=route.gateway%></a>
+ <% end %>
+ <% if route.hostname then %>
+ / <a href="http://<%=route.Hostname%>/cgi-bin-status.html"><%=route.hostname%></a>
+ <% end %>
+ </td>
+ <td class="cbi-section-table-cell"><%=route.networkInterface%></td>
+ <td class="cbi-section-table-cell"><%=route.metric%></td>
+ <td class="cbi-section-table-cell" style="background-color:<%=color%>"><%=string.format("%.3f", ETX)%></td>
+ </tr>
+ <%
+ i = ((i % 2) + 1)
+ end %>
+ </tbody>
+</table>
+
+<%+status-olsr/legend%>
+</fieldset>
+<%+status-olsr/common_js%>
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/smartgw.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/smartgw.htm
new file mode 100644
index 000000000..75d0c1c2f
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/smartgw.htm
@@ -0,0 +1,158 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+-%>
+
+<%
+local i = 1
+require("luci.model.uci")
+local uci = luci.model.uci.cursor_state()
+
+uci:foreach("olsrd", "olsrd", function(s)
+ if s.SmartGateway and s.SmartGateway == "yes" then has_smartgw = true end
+end)
+
+
+if luci.http.formvalue("status") == "1" then
+ local rv = {}
+ for k, gw in ipairs(gws) do
+ gw.tcPathCost = tonumber(gw.tcPathCost)/1024 or 0
+ if gw.tcPathCost == 4096 then
+ gw.tcPathCost = 0
+ end
+
+ rv[#rv+1] = {
+ proto = gw.proto,
+ ipAddress = gw.ipAddress,
+ status = gw.ipv4Status or gw.ipv6Status,
+ tcPathCost = string.format("%.3f", gw.tcPathCost),
+ hopCount = gw.hopCount,
+ uplinkSpeed = gw.uplinkSpeed,
+ downlinkSpeed = gw.downlinkSpeed,
+ v4 = gw.ipv4 and luci.i18n.translate('yes') or luci.i18n.translate('no'),
+ v6 = gw.ipv6 and luci.i18n.translate('yes') or luci.i18n.translate('no'),
+ externalPrefix = gw.externalPrefix
+ }
+ end
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(rv)
+ return
+end
+%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+<script type="text/javascript">//<![CDATA[
+XHR.poll(10, '<%=REQUEST_URI%>', { status: 1 },
+ function(x, info)
+ {
+ var smartgwdiv = document.getElementById('olsrd_smartgw');
+ if (smartgwdiv)
+ {
+ var s = '';
+ for (var idx = 0; idx < info.length; idx++)
+ {
+ var smartgw = info[idx];
+ s += '<tr class="cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-' + smartgw.proto + '">'
+ if (smartgw.proto == '6') {
+ linkgw = '<a href="http://[' + smartgw.ipAddress + ']/cgi-bin-status.html">' + smartgw.ipAddress + '</a>'
+ } else {
+ linkgw = '<a href="http://' + smartgw.ipAddress + '/cgi-bin-status.html">' + smartgw.ipAddress + '</a>'
+ }
+
+ s += String.format(
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>' +
+ '<td class="cbi-section-table-cell">%s</td>',
+ linkgw, smartgw.status, smartgw.tcPathCost, smartgw.hopCount, smartgw.uplinkSpeed, smartgw.downlinkSpeed, smartgw.v4, smartgw.v6, smartgw.externalPrefix
+ )
+ s += '</tr>'
+ }
+ smartgwdiv.innerHTML = s;
+ }
+}
+);
+//]]></script>
+
+
+<%+header%>
+
+<h2><a id="content" name="content"><%:SmartGW announcements%></a></h2>
+
+<div id="togglebuttons"></div>
+
+<% if has_smartgw then %>
+
+ <fieldset class="cbi-section">
+ <legend><%:Overview of smart gateways in this network%></legend>
+ <table class="cbi-section-table">
+ <thead>
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:Gateway%></th>
+ <th class="cbi-section-table-cell"><%:Status%></th>
+ <th class="cbi-section-table-cell"><%:ETX%></th>
+ <th class="cbi-section-table-cell"><%:Hops%></th>
+ <th class="cbi-section-table-cell"><%:Uplink%></th>
+ <th class="cbi-section-table-cell"><%:Downlink%></th>
+ <th class="cbi-section-table-cell"><%:IPv4%></th>
+ <th class="cbi-section-table-cell"><%:IPv6%></th>
+ <th class="cbi-section-table-cell"><%:Prefix%></th>
+
+ </tr>
+ </thead>
+
+ <tbody id="olsrd_smartgw">
+ <% for k, gw in ipairs(gws) do
+
+ gw.tcPathCost = tonumber(gw.tcPathCost)/1024 or 0
+ if gw.tcPathCost == 4096 then
+ gw.tcPathCost = 0
+ end
+ %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=proto%>">
+ <% if gw.proto == '6' then %>
+ <td class="cbi-section-table-cell"><a href="http://[<%=gw.ipAddress%>]/cgi-bin-status.html"><%=gw.ipAddress%></a></td>
+ <% else %>
+ <td class="cbi-section-table-cell"><a href="http://<%=gw.ipAddress%>/cgi-bin-status.html"><%=gw.ipAddress%></a></td>
+ <% end %>
+
+ <td class="cbi-section-table-cell"><%=gw.ipv4Status or gw.ipv6Status or '-' %></td>
+ <td class="cbi-section-table-cell"><%=string.format("%.3f", gw.tcPathCost)%></td>
+ <td class="cbi-section-table-cell"><%=gw.hopCount%></td>
+ <td class="cbi-section-table-cell"><%=gw.uplinkSpeed%></td>
+ <td class="cbi-section-table-cell"><%=gw.downlinkSpeed%></td>
+ <td class="cbi-section-table-cell"><%=gw.ipv4 and luci.i18n.translate('yes') or luci.i18n.translate('no')%></td>
+ <td class="cbi-section-table-cell"><%=gw.ipv6 and luci.i18n.translate('yes') or luci.i18n.translate('no')%></td>
+ <td class="cbi-section-table-cell"><%=gw.externalPrefix%></td>
+ </tr>
+
+ <% i = ((i % 2) + 1)
+ end %>
+ </tbody>
+ </table>
+ </fieldset>
+
+<% else %>
+
+ <%:SmartGateway is not configured on this system.%>
+
+<% end %>
+
+<%+status-olsr/common_js%>
+<%+footer%>
diff --git a/applications/luci-app-olsr/luasrc/view/status-olsr/topology.htm b/applications/luci-app-olsr/luasrc/view/status-olsr/topology.htm
new file mode 100644
index 000000000..eb3df5ff5
--- /dev/null
+++ b/applications/luci-app-olsr/luasrc/view/status-olsr/topology.htm
@@ -0,0 +1,68 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+-%>
+<%
+local i = 1
+local olsrtools = require "luci.tools.olsr"
+%>
+
+<%+header%>
+<h2><a id="content" name="content"><%:Active OLSR nodes%></a></h2>
+
+<div id="togglebuttons"></div>
+
+<fieldset class="cbi-section">
+ <legend><%:Overview of currently known OLSR nodes%></legend>
+ <table class="cbi-section-table">
+ <tr class="cbi-section-table-titles">
+ <th class="cbi-section-table-cell"><%:OLSR node%></th>
+ <th class="cbi-section-table-cell"><%:Last hop%></th>
+ <th class="cbi-section-table-cell"><%:LQ%></th>
+ <th class="cbi-section-table-cell"><%:NLQ%></th>
+ <th class="cbi-section-table-cell"><%:ETX%></th>
+ </tr>
+
+ <% for k, route in ipairs(routes) do
+ local cost = string.format("%.3f", tonumber(route.tcEdgeCost/1024) or 0)
+ local color = olsrtools.etx_color(tonumber(cost))
+ local lq = string.format("%.3f", tonumber(route.linkQuality) or 0)
+ local nlq = string.format("%.3f", tonumber(route.neighborLinkQuality) or 0)
+ %>
+
+ <tr class="cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=route.proto%>">
+
+ <% if route.proto == "6" then %>
+
+ <td class="cbi-section-table-cell"><a href="http://[<%=route.destinationIP%>]/cgi-bin-status.html"><%=route.destinationIP%></a></td>
+ <td class="cbi-section-table-cell"><a href="http://[<%=route.lastHopIP%>]/cgi-bin-status.html"><%=route.lastHopIP%></a></td>
+
+ <% else %>
+
+ <td class="cbi-section-table-cell"><a href="http://<%=route.destinationIP%>/cgi-bin-status.html"><%=route.destinationIP%></a></td>
+ <td class="cbi-section-table-cell"><a href="http://<%=route.lastHopIP%>/cgi-bin-status.html"><%=route.lastHopIP%></a></td>
+
+ <%end%>
+
+ <td class="cbi-section-table-cell"><%=lq%></td>
+ <td class="cbi-section-table-cell"><%=nlq%></td>
+ <td class="cbi-section-table-cell" style="background-color:<%=color%>"><%=cost%></td>
+ </tr>
+
+ <% i = ((i % 2) + 1)
+ end %>
+ </table>
+<%+status-olsr/legend%>
+</fieldset>
+
+<%+status-olsr/common_js%>
+<%+footer%>