1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-03-09 15:40:03 +00:00

Update luci and theme

This commit is contained in:
Ycarus 2019-05-28 21:51:29 +02:00
parent fe03553aae
commit 4d7962337f
165 changed files with 74180 additions and 13802 deletions

View file

@ -1,6 +1,5 @@
#
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
# Copyright (C) 2017-2019 Ycarus (Yannick Chabanois) <ycarus@zugaina.org>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
@ -8,9 +7,8 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI Administration - full-featured for full control
LUCI_DEPENDS:=+luci-base +luci-app-firewall +luci-lib-iptparser
LUCI_DEPENDS:=+luci-base +luci-mod-status +luci-mod-system +luci-mod-network
PKG_BUILD_DEPENDS:=iwinfo
PKG_LICENSE:=Apache-2.0
include ../luci/luci.mk

View file

@ -1,16 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polyline id="rx" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" />
<polyline id="tx" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" />
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
</svg>

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,17 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polyline id="tcp" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" />
<polyline id="udp" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" />
<polyline id="other" points="" style="fill:red;fill-opacity:0.4;stroke:red;stroke-width:1" />
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,17 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polyline id="load01" points="" style="fill:#ff0000;fill-opacity:0.4;stroke:#ff0000;stroke-width:1" />
<polyline id="load05" points="" style="fill:#ff6600;fill-opacity:0.4;stroke:#ff6600;stroke-width:1" />
<polyline id="load15" points="" style="fill:#ffaa00;fill-opacity:0.4;stroke:#ffaa00;stroke-width:1" />
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,15 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polyline id="rate" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" />
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
</svg>

Before

Width:  |  Height:  |  Size: 973 B

View file

@ -1,16 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polyline id="rssi" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" />
<polyline id="noise" points="" style="fill:red;fill-opacity:0.4;stroke:red;stroke-width:1" />
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
</svg>

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,42 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.index", package.seeall)
function index()
local root = node()
if not root.target then
root.target = alias("admin")
root.index = true
end
local page = node("admin")
page.target = firstchild()
page.title = _("Administration")
page.order = 10
page.sysauth = "root"
page.sysauth_authenticator = "htmlauth"
page.ucidata = true
page.index = true
-- Empty services menu to be populated by addons
entry({"admin", "services"}, firstchild(), _("Services"), 40).index = true
entry({"admin", "logout"}, call("action_logout"), _("Logout"), 90)
end
function action_logout()
local dsp = require "luci.dispatcher"
local utl = require "luci.util"
local sid = dsp.context.authsession
if sid then
utl.ubus("session", "destroy", { ubus_rpc_session = sid })
luci.http.header("Set-Cookie", "sysauth=%s; expires=%s; path=%s/" %{
sid, 'Thu, 01 Jan 1970 01:00:00 GMT', dsp.build_url()
})
end
luci.http.redirect(dsp.build_url())
end

View file

@ -1,473 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011-2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.network", package.seeall)
function index()
local uci = require("luci.model.uci").cursor()
local page
page = node("admin", "network")
page.target = firstchild()
page.title = _("Network")
page.order = 50
page.index = true
-- if page.inreq then
local has_switch = false
uci:foreach("network", "switch",
function(s)
has_switch = true
return false
end)
if has_switch then
page = node("admin", "network", "vlan")
page.target = cbi("admin_network/vlan")
page.title = _("Switch")
page.order = 20
page = entry({"admin", "network", "switch_status"}, call("switch_status"), nil)
page.leaf = true
end
local has_wifi = false
uci:foreach("wireless", "wifi-device",
function(s)
has_wifi = true
return false
end)
if has_wifi then
page = entry({"admin", "network", "wireless_assoclist"}, call("wifi_assoclist"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_join"}, post("wifi_join"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_add"}, post("wifi_add"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_status"}, call("wifi_status"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_reconnect"}, post("wifi_reconnect"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_scan_trigger"}, post("wifi_scan_trigger"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_scan_results"}, call("wifi_scan_results"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless"}, arcombine(cbi("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wireless"), 15)
page.leaf = true
page.subindex = true
if page.inreq then
local wdev
local net = require "luci.model.network".init(uci)
for _, wdev in ipairs(net:get_wifidevs()) do
local wnet
for _, wnet in ipairs(wdev:get_wifinets()) do
entry(
{"admin", "network", "wireless", wnet:id()},
alias("admin", "network", "wireless"),
wdev:name() .. ": " .. wnet:shortname()
)
end
end
end
end
page = entry({"admin", "network", "iface_add"}, form("admin_network/iface_add"), nil)
page.leaf = true
page = entry({"admin", "network", "iface_status"}, call("iface_status"), nil)
page.leaf = true
page = entry({"admin", "network", "iface_reconnect"}, post("iface_reconnect"), nil)
page.leaf = true
page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), _("Interfaces"), 10)
page.leaf = true
page.subindex = true
if page.inreq then
uci:foreach("network", "interface",
function (section)
local ifc = section[".name"]
if ifc ~= "loopback" then
entry({"admin", "network", "network", ifc},
true, ifc:upper())
end
end)
end
if nixio.fs.access("/etc/config/dhcp") then
page = node("admin", "network", "dhcp")
page.target = cbi("admin_network/dhcp")
page.title = _("DHCP and DNS")
page.order = 30
page = entry({"admin", "network", "dhcplease_status"}, call("lease_status"), nil)
page.leaf = true
page = node("admin", "network", "hosts")
page.target = cbi("admin_network/hosts")
page.title = _("Hostnames")
page.order = 40
end
page = node("admin", "network", "routes")
page.target = cbi("admin_network/routes")
page.title = _("Static Routes")
page.order = 50
page = node("admin", "network", "diagnostics")
page.target = template("admin_network/diagnostics")
page.title = _("Diagnostics")
page.order = 60
page = entry({"admin", "network", "diag_ping"}, post("diag_ping"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_nslookup"}, post("diag_nslookup"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_traceroute"}, post("diag_traceroute"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_ping6"}, post("diag_ping6"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_traceroute6"}, post("diag_traceroute6"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_speedtest"}, post("diag_speedtest"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_getip"}, post("diag_getip"), nil)
page.leaf = true
page = entry({"admin", "network", "diag_netstat"}, post("diag_netstat"), nil)
page.leaf = true
-- end
end
function wifi_join()
local tpl = require "luci.template"
local http = require "luci.http"
local dev = http.formvalue("device")
local ssid = http.formvalue("join")
if dev and ssid then
local cancel = (http.formvalue("cancel") or http.formvalue("cbi.cancel"))
if not cancel then
local cbi = require "luci.cbi"
local map = luci.cbi.load("admin_network/wifi_add")[1]
if map:parse() ~= cbi.FORM_DONE then
tpl.render("header")
map:render()
tpl.render("footer")
end
return
end
end
tpl.render("admin_network/wifi_join")
end
function wifi_add()
local dev = luci.http.formvalue("device")
local ntm = require "luci.model.network".init()
dev = dev and ntm:get_wifidev(dev)
if dev then
local net = dev:add_wifinet({
mode = "ap",
ssid = "OpenWrt",
encryption = "none"
})
ntm:save("wireless")
luci.http.redirect(net:adminlink())
end
end
function iface_status(ifaces)
local netm = require "luci.model.network".init()
local rv = { }
local iface
for iface in ifaces:gmatch("[%w%.%-_]+") do
local net = netm:get_network(iface)
local device = net and net:get_interface()
if device then
local data = {
id = iface,
desc = net:get_i18n(),
proto = net:proto(),
uptime = net:uptime(),
gwaddr = net:gwaddr(),
ipaddrs = net:ipaddrs(),
ip6addrs = net:ip6addrs(),
dnsaddrs = net:dnsaddrs(),
ip6prefix = net:ip6prefix(),
errors = net:errors(),
name = device:shortname(),
type = device:type(),
typename = device:get_type_i18n(),
ifname = device:name(),
macaddr = device:mac(),
is_up = net:is_up() and device:is_up(),
is_alias = net:is_alias(),
is_dynamic = net:is_dynamic(),
rx_bytes = device:rx_bytes(),
tx_bytes = device:tx_bytes(),
rx_packets = device:rx_packets(),
tx_packets = device:tx_packets(),
subdevices = { }
}
for _, device in ipairs(net:get_interfaces() or {}) do
data.subdevices[#data.subdevices+1] = {
name = device:shortname(),
type = device:type(),
typename = device:get_type_i18n(),
ifname = device:name(),
macaddr = device:mac(),
is_up = device:is_up(),
rx_bytes = device:rx_bytes(),
tx_bytes = device:tx_bytes(),
rx_packets = device:rx_packets(),
tx_packets = device:tx_packets(),
}
end
rv[#rv+1] = data
else
rv[#rv+1] = {
id = iface,
name = iface,
type = "ethernet"
}
end
end
if #rv > 0 then
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
luci.http.status(404, "No such device")
end
function iface_reconnect(iface)
local netmd = require "luci.model.network".init()
local net = netmd:get_network(iface)
if net then
luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null"
% luci.util.shellquote(iface))
luci.http.status(200, "Reconnected")
return
end
luci.http.status(404, "No such interface")
end
function wifi_status(devs)
local s = require "luci.tools.status"
local rv = { }
if type(devs) == "string" then
local dev
for dev in devs:gmatch("[%w%.%-]+") do
rv[#rv+1] = s.wifi_network(dev)
end
end
if #rv > 0 then
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
luci.http.status(404, "No such device")
end
function wifi_reconnect(radio)
local rc = luci.sys.call("env -i /sbin/wifi up %s" % luci.util.shellquote(radio))
if rc == 0 then
luci.http.status(200, "Reconnected")
else
luci.http.status(500, "Error")
end
end
function wifi_assoclist()
local s = require "luci.tools.status"
luci.http.prepare_content("application/json")
luci.http.write_json(s.wifi_assoclist())
end
local function _wifi_get_scan_results(cache_key)
local results = luci.util.ubus("session", "get", {
ubus_rpc_session = luci.model.uci:get_session_id(),
keys = { cache_key }
})
if type(results) == "table" and
type(results.values) == "table" and
type(results.values[cache_key]) == "table"
then
return results.values[cache_key]
end
return { }
end
function wifi_scan_trigger(radio, update)
local iw = radio and luci.sys.wifi.getiwinfo(radio)
if not iw then
luci.http.status(404, "No such radio device")
return
end
luci.http.status(200, "Scan scheduled")
if nixio.fork() == 0 then
io.stderr:close()
io.stdout:close()
local _, bss
local data, bssids = { }, { }
local cache_key = "scan_%s" % radio
luci.util.ubus("session", "set", {
ubus_rpc_session = luci.model.uci:get_session_id(),
values = { [cache_key] = nil }
})
for _, bss in ipairs(iw.scanlist or { }) do
data[_] = bss
bssids[bss.bssid] = bss
end
if update then
for _, bss in ipairs(_wifi_get_scan_results(cache_key)) do
if not bssids[bss.bssid] then
bss.stale = true
data[#data + 1] = bss
end
end
end
luci.util.ubus("session", "set", {
ubus_rpc_session = luci.model.uci:get_session_id(),
values = { [cache_key] = data }
})
end
end
function wifi_scan_results(radio)
local results = radio and _wifi_get_scan_results("scan_%s" % radio)
if results and #results > 0 then
luci.http.prepare_content("application/json")
luci.http.write_json(results)
else
luci.http.status(404, "No wireless scan results")
end
end
function lease_status()
local s = require "luci.tools.status"
luci.http.prepare_content("application/json")
luci.http.write('[')
luci.http.write_json(s.dhcp_leases())
luci.http.write(',')
luci.http.write_json(s.dhcp6_leases())
luci.http.write(']')
end
function switch_status(switches)
local s = require "luci.tools.status"
luci.http.prepare_content("application/json")
luci.http.write_json(s.switch_status(switches))
end
function diag_command(cmd, addr)
if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
luci.http.prepare_content("text/plain")
local util = io.popen(cmd % addr)
if util then
while true do
local ln = util:read("*l")
if not ln then break end
luci.http.write(ln)
luci.http.write("\n")
end
util:close()
end
return
end
luci.http.status(500, "Bad address")
end
function diag_ping(addr)
diag_command("ping -c 5 -W 1 %s 2>&1", addr)
end
function diag_traceroute(addr)
diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
end
function diag_nslookup(addr)
diag_command("nslookup %s 2>&1", addr)
end
function diag_ping6(addr)
diag_command("ping6 -c 5 %s 2>&1", addr)
end
function diag_traceroute6(addr)
diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
end
function diag_getip(addr)
diag_command("curl %q", addr)
end
function diag_netstat(addr)
diag_command("netstat -lapute 2>&1", "openmptcprouter.com")
end
function diag_speedtest(addr)
if addr then
diag_command("speedtestc --server %q 2>&1", addr)
else
diag_command("speedtestc 2>&1", "speedtest.net")
end
end

View file

@ -1,154 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.status", package.seeall)
function index()
entry({"admin", "status"}, alias("admin", "status", "overview"), _("Status"), 20).index = true
entry({"admin", "status", "overview"}, template("admin_status/index"), _("Overview"), 1)
entry({"admin", "status", "iptables"}, template("admin_status/iptables"), _("Firewall"), 2).leaf = true
entry({"admin", "status", "iptables_action"}, post("action_iptables")).leaf = true
entry({"admin", "status", "routes"}, template("admin_status/routes"), _("Routes"), 3)
entry({"admin", "status", "syslog"}, call("action_syslog"), _("System Log"), 4)
entry({"admin", "status", "dmesg"}, call("action_dmesg"), _("Kernel Log"), 5)
entry({"admin", "status", "processes"}, form("admin_status/processes"), _("Processes"), 6)
entry({"admin", "status", "realtime"}, alias("admin", "status", "realtime", "load"), _("Realtime Graphs"), 7)
entry({"admin", "status", "realtime", "load"}, template("admin_status/load"), _("Load"), 1).leaf = true
entry({"admin", "status", "realtime", "load_status"}, call("action_load")).leaf = true
entry({"admin", "status", "realtime", "bandwidth"}, template("admin_status/bandwidth"), _("Traffic"), 2).leaf = true
entry({"admin", "status", "realtime", "bandwidth_status"}, call("action_bandwidth")).leaf = true
if nixio.fs.access("/etc/config/wireless") then
entry({"admin", "status", "realtime", "wireless"}, template("admin_status/wireless"), _("Wireless"), 3).leaf = true
entry({"admin", "status", "realtime", "wireless_status"}, call("action_wireless")).leaf = true
end
entry({"admin", "status", "realtime", "connections"}, template("admin_status/connections"), _("Connections"), 4).leaf = true
entry({"admin", "status", "realtime", "connections_status"}, call("action_connections")).leaf = true
entry({"admin", "status", "nameinfo"}, call("action_nameinfo")).leaf = true
end
function action_syslog()
local syslog = luci.sys.syslog()
luci.template.render("admin_status/syslog", {syslog=syslog})
end
function action_dmesg()
local dmesg = luci.sys.dmesg()
luci.template.render("admin_status/dmesg", {dmesg=dmesg})
end
function action_iptables()
if luci.http.formvalue("zero") then
if luci.http.formvalue("family") == "6" then
luci.util.exec("/usr/sbin/ip6tables -Z")
else
luci.util.exec("/usr/sbin/iptables -Z")
end
elseif luci.http.formvalue("restart") then
luci.util.exec("/etc/init.d/firewall restart")
end
luci.http.redirect(luci.dispatcher.build_url("admin/status/iptables"))
end
function action_bandwidth(iface)
luci.http.prepare_content("application/json")
local bwc = io.popen("luci-bwc -i %s 2>/dev/null"
% luci.util.shellquote(iface))
if bwc then
luci.http.write("[")
while true do
local ln = bwc:read("*l")
if not ln then break end
luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end
end
function action_wireless(iface)
luci.http.prepare_content("application/json")
local bwc = io.popen("luci-bwc -r %s 2>/dev/null"
% luci.util.shellquote(iface))
if bwc then
luci.http.write("[")
while true do
local ln = bwc:read("*l")
if not ln then break end
luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end
end
function action_load()
luci.http.prepare_content("application/json")
local bwc = io.popen("luci-bwc -l 2>/dev/null")
if bwc then
luci.http.write("[")
while true do
local ln = bwc:read("*l")
if not ln then break end
luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end
end
function action_connections()
local sys = require "luci.sys"
luci.http.prepare_content("application/json")
luci.http.write('{ "connections": ')
luci.http.write_json(sys.net.conntrack())
local bwc = io.popen("luci-bwc -c 2>/dev/null")
if bwc then
luci.http.write(', "statistics": [')
while true do
local ln = bwc:read("*l")
if not ln then break end
luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end
luci.http.write(" }")
end
function action_nameinfo(...)
local util = require "luci.util"
luci.http.prepare_content("application/json")
luci.http.write_json(util.ubus("network.rrdns", "lookup", {
addrs = { ... },
timeout = 5000,
limit = 1000
}) or { })
end

View file

@ -1,448 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.system", package.seeall)
function index()
local fs = require "nixio.fs"
entry({"admin", "system"}, alias("admin", "system", "system"), _("System"), 30).index = true
entry({"admin", "system", "system"}, cbi("admin_system/system"), _("System"), 1)
entry({"admin", "system", "clock_status"}, post_on({ set = true }, "action_clock_status"))
entry({"admin", "system", "admin"}, cbi("admin_system/admin"), _("Administration"), 2)
if fs.access("/bin/opkg") then
entry({"admin", "system", "packages"}, post_on({ exec = "1" }, "action_packages"), _("Software"), 10)
entry({"admin", "system", "packages", "ipkg"}, form("admin_system/ipkg"))
end
entry({"admin", "system", "startup"}, form("admin_system/startup"), _("Startup"), 45)
entry({"admin", "system", "crontab"}, form("admin_system/crontab"), _("Scheduled Tasks"), 46)
if fs.access("/sbin/block") and fs.access("/etc/config/fstab") then
entry({"admin", "system", "fstab"}, cbi("admin_system/fstab"), _("Mount Points"), 50)
entry({"admin", "system", "fstab", "mount"}, cbi("admin_system/fstab/mount"), nil).leaf = true
entry({"admin", "system", "fstab", "swap"}, cbi("admin_system/fstab/swap"), nil).leaf = true
end
local nodes, number = fs.glob("/sys/class/leds/*")
if number > 0 then
entry({"admin", "system", "leds"}, cbi("admin_system/leds"), _("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), 60)
end
entry({"admin", "system", "flashops"}, call("action_flashops"), _("Backup / Flash Firmware"), 70)
entry({"admin", "system", "flashops", "reset"}, post("action_reset"))
entry({"admin", "system", "flashops", "backup"}, post("action_backup"))
entry({"admin", "system", "flashops", "backupfiles"}, form("admin_system/backupfiles"))
-- call() instead of post() due to upload handling!
entry({"admin", "system", "flashops", "restore"}, call("action_restore"))
entry({"admin", "system", "flashops", "sysupgrade"}, call("action_sysupgrade"))
entry({"admin", "system", "reboot"}, template("admin_system/reboot"), _("Reboot"), 90)
entry({"admin", "system", "reboot", "call"}, post("action_reboot"))
end
function action_clock_status()
local set = tonumber(luci.http.formvalue("set"))
if set ~= nil and set > 0 then
local date = os.date("*t", set)
if date then
luci.sys.call("date -s '%04d-%02d-%02d %02d:%02d:%02d'" %{
date.year, date.month, date.day, date.hour, date.min, date.sec
})
luci.sys.call("/etc/init.d/sysfixtime restart")
end
end
luci.http.prepare_content("application/json")
luci.http.write_json({ timestring = os.date("%c") })
end
function action_packages()
local fs = require "nixio.fs"
local ipkg = require "luci.model.ipkg"
local submit = (luci.http.formvalue("exec") == "1")
local update, upgrade
local changes = false
local install = { }
local remove = { }
local stdout = { "" }
local stderr = { "" }
local out, err
-- Display
local display = luci.http.formvalue("display") or "available"
-- Letter
local letter = string.byte(luci.http.formvalue("letter") or "A", 1)
letter = (letter == 35 or (letter >= 65 and letter <= 90)) and letter or 65
-- Search query
local query = luci.http.formvalue("query")
query = (query ~= '') and query or nil
-- Modifying actions
if submit then
-- Packets to be installed
local ninst = luci.http.formvalue("install")
local uinst = nil
-- Install from URL
local url = luci.http.formvalue("url")
if url and url ~= '' then
uinst = url
end
-- Do install
if ninst then
install[ninst], out, err = ipkg.install(ninst)
stdout[#stdout+1] = out
stderr[#stderr+1] = err
changes = true
end
if uinst then
local pkg
for pkg in luci.util.imatch(uinst) do
install[uinst], out, err = ipkg.install(pkg)
stdout[#stdout+1] = out
stderr[#stderr+1] = err
changes = true
end
end
-- Remove packets
local rem = luci.http.formvalue("remove")
if rem then
remove[rem], out, err = ipkg.remove(rem)
stdout[#stdout+1] = out
stderr[#stderr+1] = err
changes = true
end
-- Update all packets
update = luci.http.formvalue("update")
if update then
update, out, err = ipkg.update()
stdout[#stdout+1] = out
stderr[#stderr+1] = err
end
-- Upgrade all packets
upgrade = luci.http.formvalue("upgrade")
if upgrade then
upgrade, out, err = ipkg.upgrade()
stdout[#stdout+1] = out
stderr[#stderr+1] = err
end
end
-- List state
local no_lists = true
local old_lists = false
if fs.access("/var/opkg-lists/") then
local list
for list in fs.dir("/var/opkg-lists/") do
no_lists = false
if (fs.stat("/var/opkg-lists/"..list, "mtime") or 0) < (os.time() - (24 * 60 * 60)) then
old_lists = true
break
end
end
end
luci.template.render("admin_system/packages", {
display = display,
letter = letter,
query = query,
install = install,
remove = remove,
update = update,
upgrade = upgrade,
no_lists = no_lists,
old_lists = old_lists,
stdout = table.concat(stdout, ""),
stderr = table.concat(stderr, "")
})
-- Remove index cache
if changes then
fs.unlink("/tmp/luci-indexcache")
end
end
local function image_supported(image)
return (os.execute("sysupgrade -T %q >/dev/null" % image) == 0)
end
local function image_checksum(image)
return (luci.sys.exec("md5sum %q" % image):match("^([^%s]+)"))
end
local function image_sha256_checksum(image)
return (luci.sys.exec("sha256sum %q" % image):match("^([^%s]+)"))
end
local function supports_sysupgrade()
return nixio.fs.access("/lib/upgrade/platform.sh")
end
local function supports_reset()
return (os.execute([[grep -sq "^overlayfs:/overlay / overlay " /proc/mounts]]) == 0)
end
local function storage_size()
local size = 0
if nixio.fs.access("/proc/mtd") then
for l in io.lines("/proc/mtd") do
local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"')
if n == "linux" or n == "firmware" then
size = tonumber(s, 16)
break
end
end
elseif nixio.fs.access("/proc/partitions") then
for l in io.lines("/proc/partitions") do
local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)')
if b and n and not n:match('[0-9]') then
size = tonumber(b) * 1024
break
end
end
end
return size
end
function action_flashops()
--
-- Overview
--
luci.template.render("admin_system/flashops", {
reset_avail = supports_reset(),
upgrade_avail = supports_sysupgrade()
})
end
function action_sysupgrade()
local fs = require "nixio.fs"
local http = require "luci.http"
local image_tmp = "/tmp/firmware.img"
local fp
http.setfilehandler(
function(meta, chunk, eof)
if not fp and meta and meta.name == "image" then
fp = io.open(image_tmp, "w")
end
if fp and chunk then
fp:write(chunk)
end
if fp and eof then
fp:close()
end
end
)
if not luci.dispatcher.test_post_security() then
fs.unlink(image_tmp)
return
end
--
-- Cancel firmware flash
--
if http.formvalue("cancel") then
fs.unlink(image_tmp)
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
return
end
--
-- Initiate firmware flash
--
local step = tonumber(http.formvalue("step") or 1)
if step == 1 then
if image_supported(image_tmp) then
luci.template.render("admin_system/upgrade", {
checksum = image_checksum(image_tmp),
sha256ch = image_sha256_checksum(image_tmp),
storage = storage_size(),
size = (fs.stat(image_tmp, "size") or 0),
keep = (not not http.formvalue("keep"))
})
else
fs.unlink(image_tmp)
luci.template.render("admin_system/flashops", {
reset_avail = supports_reset(),
upgrade_avail = supports_sysupgrade(),
image_invalid = true
})
end
--
-- Start sysupgrade flash
--
elseif step == 2 then
local keep = (http.formvalue("keep") == "1") and "" or "-n"
luci.template.render("admin_system/applyreboot", {
title = luci.i18n.translate("Flashing..."),
msg = luci.i18n.translate("The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
addr = (#keep > 0) and "192.168.1.1" or nil
})
fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %q" %{ keep, image_tmp })
end
end
function action_backup()
local reader = ltn12_popen("sysupgrade --create-backup - 2>/dev/null")
luci.http.header(
'Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' %{
luci.sys.hostname(),
os.date("%Y-%m-%d")
})
luci.http.prepare_content("application/x-targz")
luci.ltn12.pump.all(reader, luci.http.write)
end
function action_restore()
local fs = require "nixio.fs"
local http = require "luci.http"
local archive_tmp = "/tmp/restore.tar.gz"
local fp
http.setfilehandler(
function(meta, chunk, eof)
if not fp and meta and meta.name == "archive" then
fp = io.open(archive_tmp, "w")
end
if fp and chunk then
fp:write(chunk)
end
if fp and eof then
fp:close()
end
end
)
if not luci.dispatcher.test_post_security() then
fs.unlink(archive_tmp)
return
end
local upload = http.formvalue("archive")
if upload and #upload > 0 then
if os.execute("gunzip -t %q >/dev/null 2>&1" % archive_tmp) == 0 then
luci.template.render("admin_system/applyreboot")
os.execute("tar -C / -xzf %q >/dev/null 2>&1" % archive_tmp)
luci.sys.reboot()
else
luci.template.render("admin_system/flashops", {
reset_avail = supports_reset(),
upgrade_avail = supports_sysupgrade(),
backup_invalid = true
})
end
return
end
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
end
function action_reset()
if supports_reset() then
luci.template.render("admin_system/applyreboot", {
title = luci.i18n.translate("Erasing..."),
msg = luci.i18n.translate("The system is erasing the configuration partition now and will reboot itself when finished."),
addr = "192.168.1.1"
})
fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; jffs2reset -y && reboot")
return
end
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
end
function action_passwd()
local p1 = luci.http.formvalue("pwd1")
local p2 = luci.http.formvalue("pwd2")
local stat = nil
if p1 or p2 then
if p1 == p2 then
stat = luci.sys.user.setpasswd("root", p1)
else
stat = 10
end
end
luci.template.render("admin_system/passwd", {stat=stat})
end
function action_reboot()
luci.sys.reboot()
end
function fork_exec(command)
local pid = nixio.fork()
if pid > 0 then
return
elseif pid == 0 then
-- change to root dir
nixio.chdir("/")
-- patch stdin, out, err to /dev/null
local null = nixio.open("/dev/null", "w+")
if null then
nixio.dup(null, nixio.stderr)
nixio.dup(null, nixio.stdout)
nixio.dup(null, nixio.stdin)
if null:fileno() > 2 then
null:close()
end
end
-- replace with target command
nixio.exec("/bin/sh", "-c", command)
end
end
function ltn12_popen(command)
local fdi, fdo = nixio.pipe()
local pid = nixio.fork()
if pid > 0 then
fdo:close()
local close
return function()
local buffer = fdi:read(2048)
local wpid, stat = nixio.waitpid(pid, "nohang")
if not close and wpid and stat == "exited" then
close = true
end
if buffer and #buffer > 0 then
return buffer
elseif close then
fdi:close()
return nil
end
end
elseif pid == 0 then
nixio.dup(fdo, nixio.stdout)
fdi:close()
fdo:close()
nixio.exec("/bin/sh", "-c", command)
end
end

View file

@ -1,109 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2010-2015 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.admin.uci", package.seeall)
function index()
local redir = luci.http.formvalue("redir", true)
or table.concat(luci.dispatcher.context.request, "/")
entry({"admin", "uci"}, nil, _("Configuration"))
entry({"admin", "uci", "changes"}, post_on({ trigger_apply = true }, "action_changes"), _("Changes"), 40).query = {redir=redir}
entry({"admin", "uci", "revert"}, post("action_revert"), _("Revert"), 30).query = {redir=redir}
local node
local authen = function(checkpass, allowed_users)
return "root", luci.http.formvalue("sid")
end
node = entry({"admin", "uci", "apply_rollback"}, post("action_apply_rollback"), nil)
node.cors = true
node.sysauth_authenticator = authen
node = entry({"admin", "uci", "apply_unchecked"}, post("action_apply_unchecked"), nil)
node.cors = true
node.sysauth_authenticator = authen
node = entry({"admin", "uci", "confirm"}, call("action_confirm"), nil)
node.cors = true
node.sysauth = false
end
function action_changes()
local uci = require "luci.model.uci"
local changes = uci:changes()
luci.template.render("admin_uci/changes", {
changes = next(changes) and changes,
timeout = timeout,
trigger_apply = luci.http.formvalue("trigger_apply") and true or false
})
end
function action_revert()
local uci = require "luci.model.uci"
local changes = uci:changes()
-- Collect files to be reverted
local r, tbl
for r, tbl in pairs(changes) do
uci:revert(r)
end
luci.template.render("admin_uci/revert", {
changes = next(changes) and changes,
trigger_revert = true
})
end
local function ubus_state_to_http(errstr)
local map = {
["Invalid command"] = 400,
["Invalid argument"] = 400,
["Method not found"] = 404,
["Entry not found"] = 404,
["No data"] = 204,
["Permission denied"] = 403,
["Timeout"] = 504,
["Not supported"] = 500,
["Unknown error"] = 500,
["Connection failed"] = 503
}
local code = map[errstr] or 200
local msg = errstr or "OK"
luci.http.status(code, msg)
if code ~= 204 then
luci.http.prepare_content("text/plain")
luci.http.write(msg)
end
end
function action_apply_rollback()
local uci = require "luci.model.uci"
local token, errstr = uci:apply(true)
if token then
luci.http.prepare_content("application/json")
luci.http.write_json({ token = token })
else
ubus_state_to_http(errstr)
end
end
function action_apply_unchecked()
local uci = require "luci.model.uci"
local _, errstr = uci:apply(false)
ubus_state_to_http(errstr)
end
function action_confirm()
local uci = require "luci.model.uci"
local token = luci.http.formvalue("token")
local _, errstr = uci:confirm(token)
ubus_state_to_http(errstr)
end

View file

@ -1,349 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
local ipc = require "luci.ip"
local sys = require "luci.sys"
local o
require "luci.util"
m = Map("dhcp", translate("DHCP and DNS"),
translate("Dnsmasq is a combined <abbr title=\"Dynamic Host Configuration Protocol" ..
"\">DHCP</abbr>-Server and <abbr title=\"Domain Name System\">DNS</abbr>-" ..
"Forwarder for <abbr title=\"Network Address Translation\">NAT</abbr> " ..
"firewalls"))
s = m:section(TypedSection, "dnsmasq", translate("Server Settings"))
s.anonymous = true
s.addremove = false
s:tab("general", translate("General Settings"))
s:tab("files", translate("Resolv and Hosts Files"))
s:tab("tftp", translate("TFTP Settings"))
s:tab("advanced", translate("Advanced Settings"))
s:taboption("general", Flag, "domainneeded",
translate("Domain required"),
translate("Don't forward <abbr title=\"Domain Name System\">DNS</abbr>-Requests without " ..
"<abbr title=\"Domain Name System\">DNS</abbr>-Name"))
s:taboption("general", Flag, "authoritative",
translate("Authoritative"),
translate("This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" ..
"abbr> in the local network"))
s:taboption("files", Flag, "readethers",
translate("Use <code>/etc/ethers</code>"),
translate("Read <code>/etc/ethers</code> to configure the <abbr title=\"Dynamic Host " ..
"Configuration Protocol\">DHCP</abbr>-Server"))
s:taboption("files", Value, "leasefile",
translate("Leasefile"),
translate("file where given <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</" ..
"abbr>-leases will be stored"))
s:taboption("files", Flag, "noresolv",
translate("Ignore resolve file")).optional = true
rf = s:taboption("files", Value, "resolvfile",
translate("Resolve file"),
translate("local <abbr title=\"Domain Name System\">DNS</abbr> file"))
rf:depends("noresolv", "")
rf.optional = true
s:taboption("files", Flag, "nohosts",
translate("Ignore <code>/etc/hosts</code>")).optional = true
s:taboption("files", DynamicList, "addnhosts",
translate("Additional Hosts files")).optional = true
qu = s:taboption("advanced", Flag, "quietdhcp",
translate("Suppress logging"),
translate("Suppress logging of the routine operation of these protocols"))
qu.optional = true
se = s:taboption("advanced", Flag, "sequential_ip",
translate("Allocate IP sequentially"),
translate("Allocate IP addresses sequentially, starting from the lowest available address"))
se.optional = true
bp = s:taboption("advanced", Flag, "boguspriv",
translate("Filter private"),
translate("Do not forward reverse lookups for local networks"))
bp.default = bp.enabled
s:taboption("advanced", Flag, "filterwin2k",
translate("Filter useless"),
translate("Do not forward requests that cannot be answered by public name servers"))
s:taboption("advanced", Flag, "localise_queries",
translate("Localise queries"),
translate("Localise hostname depending on the requesting subnet if multiple IPs are available"))
local have_dnssec_support = luci.util.checklib("/usr/sbin/dnsmasq", "libhogweed.so")
if have_dnssec_support then
o = s:taboption("advanced", Flag, "dnssec",
translate("DNSSEC"))
o.optional = true
o = s:taboption("advanced", Flag, "dnsseccheckunsigned",
translate("DNSSEC check unsigned"),
translate("Requires upstream supports DNSSEC; verify unsigned domain responses really come from unsigned domains"))
o.optional = true
end
s:taboption("general", Value, "local",
translate("Local server"),
translate("Local domain specification. Names matching this domain are never forwarded and are resolved from DHCP or hosts files only"))
s:taboption("general", Value, "domain",
translate("Local domain"),
translate("Local domain suffix appended to DHCP names and hosts file entries"))
s:taboption("advanced", Flag, "expandhosts",
translate("Expand hosts"),
translate("Add local domain suffix to names served from hosts files"))
s:taboption("advanced", Flag, "nonegcache",
translate("No negative cache"),
translate("Do not cache negative replies, e.g. for not existing domains"))
s:taboption("advanced", Value, "serversfile",
translate("Additional servers file"),
translate("This file may contain lines like 'server=/domain/1.2.3.4' or 'server=1.2.3.4' for"..
"domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers."))
s:taboption("advanced", Flag, "strictorder",
translate("Strict order"),
translate("<abbr title=\"Domain Name System\">DNS</abbr> servers will be queried in the " ..
"order of the resolvfile")).optional = true
s:taboption("advanced", Flag, "allservers",
translate("All Servers"),
translate("Query all available upstream <abbr title=\"Domain Name System\">DNS</abbr> servers")).optional = true
bn = s:taboption("advanced", DynamicList, "bogusnxdomain", translate("Bogus NX Domain Override"),
translate("List of hosts that supply bogus NX domain results"))
bn.optional = true
bn.placeholder = "67.215.65.132"
s:taboption("general", Flag, "logqueries",
translate("Log queries"),
translate("Write received DNS requests to syslog")).optional = true
df = s:taboption("general", DynamicList, "server", translate("DNS forwardings"),
translate("List of <abbr title=\"Domain Name System\">DNS</abbr> " ..
"servers to forward requests to"))
df.optional = true
df.placeholder = "/example.org/10.1.2.3"
rp = s:taboption("general", Flag, "rebind_protection",
translate("Rebind protection"),
translate("Discard upstream RFC1918 responses"))
rp.rmempty = false
rl = s:taboption("general", Flag, "rebind_localhost",
translate("Allow localhost"),
translate("Allow upstream responses in the 127.0.0.0/8 range, e.g. for RBL services"))
rl:depends("rebind_protection", "1")
rd = s:taboption("general", DynamicList, "rebind_domain",
translate("Domain whitelist"),
translate("List of domains to allow RFC1918 responses for"))
rd.optional = true
rd:depends("rebind_protection", "1")
rd.datatype = "host(1)"
rd.placeholder = "ihost.netflix.com"
pt = s:taboption("advanced", Value, "port",
translate("<abbr title=\"Domain Name System\">DNS</abbr> server port"),
translate("Listening port for inbound DNS queries"))
pt.optional = true
pt.datatype = "port"
pt.placeholder = 53
qp = s:taboption("advanced", Value, "queryport",
translate("<abbr title=\"Domain Name System\">DNS</abbr> query port"),
translate("Fixed source port for outbound DNS queries"))
qp.optional = true
qp.datatype = "port"
qp.placeholder = translate("any")
lm = s:taboption("advanced", Value, "dhcpleasemax",
translate("<abbr title=\"maximal\">Max.</abbr> <abbr title=\"Dynamic Host Configuration " ..
"Protocol\">DHCP</abbr> leases"),
translate("Maximum allowed number of active DHCP leases"))
lm.optional = true
lm.datatype = "uinteger"
lm.placeholder = translate("unlimited")
em = s:taboption("advanced", Value, "ednspacket_max",
translate("<abbr title=\"maximal\">Max.</abbr> <abbr title=\"Extension Mechanisms for " ..
"Domain Name System\">EDNS0</abbr> packet size"),
translate("Maximum allowed size of EDNS.0 UDP packets"))
em.optional = true
em.datatype = "uinteger"
em.placeholder = 1280
cq = s:taboption("advanced", Value, "dnsforwardmax",
translate("<abbr title=\"maximal\">Max.</abbr> concurrent queries"),
translate("Maximum allowed number of concurrent DNS queries"))
cq.optional = true
cq.datatype = "uinteger"
cq.placeholder = 150
cs = s:taboption("advanced", Value, "cachesize",
translate("Size of DNS query cache"),
translate("Number of cached DNS entries (max is 10000, 0 is no caching)"))
cs.optional = true
cs.datatype = "range(0,10000)"
cs.placeholder = 150
s:taboption("tftp", Flag, "enable_tftp",
translate("Enable TFTP server")).optional = true
tr = s:taboption("tftp", Value, "tftp_root",
translate("TFTP server root"),
translate("Root directory for files served via TFTP"))
tr.optional = true
tr:depends("enable_tftp", "1")
tr.placeholder = "/"
db = s:taboption("tftp", Value, "dhcp_boot",
translate("Network boot image"),
translate("Filename of the boot image advertised to clients"))
db.optional = true
db:depends("enable_tftp", "1")
db.placeholder = "pxelinux.0"
o = s:taboption("general", Flag, "localservice",
translate("Local Service Only"),
translate("Limit DNS service to subnets interfaces on which we are serving DNS."))
o.optional = false
o.rmempty = false
o = s:taboption("general", Flag, "nonwildcard",
translate("Non-wildcard"),
translate("Bind only to specific interfaces rather than wildcard address."))
o.optional = false
o.rmempty = false
o = s:taboption("general", DynamicList, "interface",
translate("Listen Interfaces"),
translate("Limit listening to these interfaces, and loopback."))
o.optional = true
o:depends("nonwildcard", true)
o = s:taboption("general", DynamicList, "notinterface",
translate("Exclude interfaces"),
translate("Prevent listening on these interfaces."))
o.optional = true
o:depends("nonwildcard", true)
m:section(SimpleSection).template = "admin_network/lease_status"
s = m:section(TypedSection, "host", translate("Static Leases"),
translate("Static leases are used to assign fixed IP addresses and symbolic hostnames to " ..
"DHCP clients. They are also required for non-dynamic interface configurations where " ..
"only hosts with a corresponding lease are served.") .. "<br />" ..
translate("Use the <em>Add</em> Button to add a new lease entry. The <em>MAC-Address</em> " ..
"identifies the host, the <em>IPv4-Address</em> specifies the fixed address to " ..
"use, and the <em>Hostname</em> is assigned as a symbolic name to the requesting host. " ..
"The optional <em>Lease time</em> can be used to set non-standard host-specific " ..
"lease time, e.g. 12h, 3d or infinite."))
s.addremove = true
s.anonymous = true
s.template = "cbi/tblsection"
name = s:option(Value, "name", translate("Hostname"))
name.datatype = "hostname('strict')"
name.rmempty = true
function name.write(self, section, value)
Value.write(self, section, value)
m:set(section, "dns", "1")
end
function name.remove(self, section)
Value.remove(self, section)
m:del(section, "dns")
end
mac = s:option(Value, "mac", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
mac.datatype = "list(macaddr)"
mac.rmempty = true
function mac.cfgvalue(self, section)
local val = Value.cfgvalue(self, section)
return ipc.checkmac(val) or val
end
ip = s:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
ip.datatype = "or(ip4addr,'ignore')"
gw = s:option(Value, "gw", translate("Gateway"))
gw.datatype = "or(ip4addr,'ignore')"
time = s:option(Value, "leasetime", translate("Lease time"))
time.rmempty = true
duid = s:option(Value, "duid", translate("<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"))
duid.datatype = "and(rangelength(20,36),hexstring)"
fp = io.open("/var/hosts/odhcpd")
if fp then
for line in fp:lines() do
local net_val, duid_val = string.match(line, "# (%S+)%s+(%S+)")
if duid_val then
duid:value(duid_val, duid_val)
end
end
fp:close()
end
hostid = s:option(Value, "hostid", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Suffix (hex)"))
sys.net.host_hints(function(m, v4, v6, name)
if m and v4 then
ip:value(v4)
mac:value(m, "%s (%s)" %{ m, name or v4 })
end
end)
function ip.validate(self, value, section)
local m = mac:formvalue(section) or ""
local n = name:formvalue(section) or ""
if value and #n == 0 and #m == 0 then
return nil, translate("One of hostname or mac address must be specified!")
end
return Value.validate(self, value, section)
end
return m

View file

@ -1,31 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2010-2015 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local ipc = require "luci.ip"
local sys = require "luci.sys"
m = Map("dhcp", translate("Hostnames"))
s = m:section(TypedSection, "domain", translate("Host entries"))
s.addremove = true
s.anonymous = true
s.template = "cbi/tblsection"
hn = s:option(Value, "name", translate("Hostname"))
hn.datatype = "hostname"
hn.rmempty = true
ip = s:option(Value, "ip", translate("IP address"))
ip.datatype = "ipaddr"
ip.rmempty = true
sys.net.host_hints(function(mac, v4, v6, name)
v6 = v6 and ipc.IPv6(v6)
if v4 or (v6 and not v6:is6linklocal()) then
ip:value(tostring(v4 or v6), "%s (%s)" %{ tostring(v4 or v6), name or mac })
end
end)
return m

View file

@ -1,117 +0,0 @@
-- Copyright 2009-2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local nw = require "luci.model.network".init()
local fw = require "luci.model.firewall".init()
local utl = require "luci.util"
local uci = require "luci.model.uci".cursor()
m = SimpleForm("network", translate("Create Interface"))
m.redirect = luci.dispatcher.build_url("admin/network/network")
m.reset = false
function m.on_cancel()
luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
end
newnet = m:field(Value, "_netname", translate("Name of the new interface"),
translate("The allowed characters are: <code>A-Z</code>, <code>a-z</code>, " ..
"<code>0-9</code> and <code>_</code>"
))
newnet:depends("_attach", "")
newnet.default = arg[1] and "net_" .. arg[1]:gsub("[^%w_]+", "_")
newnet.datatype = "and(uciname,maxlength(15))"
advice = m:field(DummyValue, "d1", translate("Note: interface name length"),
translate("Maximum length of the name is 15 characters including " ..
"the automatic protocol/bridge prefix (br-, 6in4-, pppoe- etc.)"
))
newproto = m:field(ListValue, "_netproto", translate("Protocol of the new interface"))
--netbridge = m:field(Flag, "_bridge", translate("Create a bridge over multiple interfaces"))
newtype = m:field(ListValue, "_type", translate("Type of the new interface"))
newtype:value("", translate("Default"))
newtype:value("macvlan", translate("Create a macvlan sub interface"))
newtype:value("bridge", translate("Create a bridge over multiple interfaces"))
sifname = m:field(Value, "_ifname", translate("Cover the following interface"))
sifname.widget = "radio"
sifname.template = "cbi/network_ifacelist"
sifname.nobridges = true
mifname = m:field(Value, "_ifnames", translate("Cover the following interfaces"))
mifname.widget = "checkbox"
mifname.template = "cbi/network_ifacelist"
mifname.nobridges = true
vifname = m:field(Value, "_vifname", translate("Cover the following interface"))
vifname.default = "eth0"
local _, p
for _, p in ipairs(nw:get_protocols()) do
if p:is_installed() then
newproto:value(p:proto(), p:get_i18n())
--if not p:is_virtual() then netbridge:depends("_netproto", p:proto()) end
if not p:is_virtual() then newtype:depends("_netproto", p:proto()) end
if not p:is_floating() then
--sifname:depends({ _bridge = "", _netproto = p:proto()})
--mifname:depends({ _bridge = "1", _netproto = p:proto()})
sifname:depends({ _type = "", _netproto = p:proto() })
mifname:depends({ _type = "bridge", _netproto = p:proto() })
vifname:depends({ _type = "macvlan", _netproto = p:proto() })
end
end
end
function newproto.validate(self, value, section)
local name = newnet:formvalue(section)
if not name or #name == 0 then
newnet:add_error(section, translate("No network name specified"))
elseif m:get(name) then
newnet:add_error(section, translate("The given network name is not unique"))
end
local proto = nw:get_protocol(value)
if proto and not proto:is_floating() then
--local br = (netbridge:formvalue(section) == "1")
--local ifn = br and mifname:formvalue(section) or sifname:formvalue(section)
local ifn = ( (newtype:formvalue(section) == "macvlan" and name) or (newtype:formvalue(section) == "bridge" and mifname:formvalue(section)) or sifname:formvalue(section) )
for ifn in utl.imatch(ifn) do
return value
end
return nil, translate("The selected protocol needs a device assigned")
end
return value
end
function newproto.write(self, section, value)
local name = newnet:formvalue(section)
if name and #name > 0 then
--local br = (netbridge:formvalue(section) == "1") and "bridge" or nil
--local net = nw:add_network(name, { proto = value, type = br })
local isBridge = (newtype:formvalue(section) == "bridge") or nil
local isMacvlan = (newtype:formvalue(section) == "macvlan") or nil
local net = nw:add_network(name, { proto = value, type = newtype:formvalue(section), interface = isMacvlan and vifname:formvalue(section) or nil })
if net then
local ifn
--br and mifname:formvalue(section) or sifname:formvalue(section)
for ifn in utl.imatch(
(isMacvlan and name) or (isBridge and mifname:formvalue(section)) or (sifname:formvalue(section))
) do
net:add_interface(ifn)
end
nw:save("network")
nw:save("wireless")
end
luci.http.redirect(luci.dispatcher.build_url("admin/network/network", name))
end
end
return m

View file

@ -1,593 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local ut = require "luci.util"
local pt = require "luci.tools.proto"
local nw = require "luci.model.network"
local fw = require "luci.model.firewall"
arg[1] = arg[1] or ""
local has_dnsmasq = fs.access("/etc/config/dhcp")
local has_firewall = fs.access("/etc/config/firewall")
m = Map("network", translate("Interfaces") .. " - " .. arg[1]:upper(), translate("On this page you can configure the network interfaces. You can bridge several interfaces by ticking the \"bridge interfaces\" field and enter the names of several network interfaces separated by spaces. You can also use <abbr title=\"Virtual Local Area Network\">VLAN</abbr> notation <samp>INTERFACE.VLANNR</samp> (<abbr title=\"for example\">e.g.</abbr>: <samp>eth0.1</samp>)."))
m.redirect = luci.dispatcher.build_url("admin", "network", "network")
m:chain("wireless")
m:chain("luci")
if has_firewall then
m:chain("firewall")
end
nw.init(m.uci)
fw.init(m.uci)
local net = nw:get_network(arg[1])
local function set_ifstate(name, option, value)
local found = false
m.uci:foreach("luci", "ifstate", function (s)
if s.interface == name then
m.uci:set("luci", s[".name"], option, value)
found = true
return false
end
end)
if not found then
local sid = m.uci:add("luci", "ifstate")
m.uci:set("luci", sid, "interface", name)
m.uci:set("luci", sid, option, value)
end
m.uci:save("luci")
end
local function get_ifstate(name, option)
local val
m.uci:foreach("luci", "ifstate", function (s)
if s.interface == name then
val = m.uci:get("luci", s[".name"], option)
return false
end
end)
return val
end
local function backup_ifnames(is_bridge)
if not net:is_floating() and not get_ifstate(net:name(), "ifname") then
local ifcs = net:get_interfaces() or { net:get_interface() }
if ifcs then
local _, ifn
local ifns = { }
for _, ifn in ipairs(ifcs) do
local wif = ifn:get_wifinet()
ifns[#ifns+1] = wif and wif:id() or ifn:name()
end
if #ifns > 0 then
set_ifstate(net:name(), "ifname", table.concat(ifns, " "))
set_ifstate(net:name(), "bridge", tostring(net:is_bridge()))
end
end
end
end
-- redirect to overview page if network does not exist anymore (e.g. after a revert)
if not net then
luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
return
end
-- protocol switch was requested, rebuild interface config and reload page
if m:formvalue("cbid.network.%s._switch" % net:name()) then
-- get new protocol
local ptype = m:formvalue("cbid.network.%s.proto" % net:name()) or "-"
local proto = nw:get_protocol(ptype, net:name())
if proto then
-- backup default
backup_ifnames()
-- if current proto is not floating and target proto is not floating,
-- then attempt to retain the ifnames
--error(net:proto() .. " > " .. proto:proto())
if not net:is_floating() and not proto:is_floating() then
-- if old proto is a bridge and new proto not, then clip the
-- interface list to the first ifname only
if net:is_bridge() and proto:is_virtual() then
local _, ifn
local first = true
for _, ifn in ipairs(net:get_interfaces() or { net:get_interface() }) do
if first then
first = false
else
net:del_interface(ifn)
end
end
m:del(net:name(), "type")
end
-- if the current proto is floating, the target proto not floating,
-- then attempt to restore ifnames from backup
elseif net:is_floating() and not proto:is_floating() then
-- if we have backup data, then re-add all orphaned interfaces
-- from it and restore the bridge choice
local br = (get_ifstate(net:name(), "bridge") == "true")
local ifn
local ifns = { }
for ifn in ut.imatch(get_ifstate(net:name(), "ifname")) do
ifn = nw:get_interface(ifn)
if ifn and not ifn:get_network() then
proto:add_interface(ifn)
if not br then
break
end
end
end
if br then
m:set(net:name(), "type", "bridge")
end
-- in all other cases clear the ifnames
else
local _, ifc
for _, ifc in ipairs(net:get_interfaces() or { net:get_interface() }) do
net:del_interface(ifc)
end
m:del(net:name(), "type")
end
-- clear options
local k, v
for k, v in pairs(m:get(net:name())) do
if k:sub(1,1) ~= "." and
k ~= "type" and
k ~= "ifname"
then
m:del(net:name(), k)
end
end
-- set proto
m:set(net:name(), "proto", proto:proto())
m.uci:save("network")
m.uci:save("wireless")
-- reload page
luci.http.redirect(luci.dispatcher.build_url("admin/network/network", arg[1]))
return
end
end
-- dhcp setup was requested, create section and reload page
if m:formvalue("cbid.dhcp._enable._enable") then
m.uci:section("dhcp", "dhcp", arg[1], {
interface = arg[1],
start = "100",
limit = "150",
leasetime = "12h"
})
m.uci:save("dhcp")
luci.http.redirect(luci.dispatcher.build_url("admin/network/network", arg[1]))
return
end
local ifc = net:get_interface()
s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
s.addremove = false
s:tab("general", translate("General Setup"))
s:tab("advanced", translate("Advanced Settings"))
s:tab("physical", translate("Physical Settings"))
if has_firewall then
s:tab("firewall", translate("Firewall Settings"))
end
st = s:taboption("general", DummyValue, "__status", translate("Status"))
local function set_status()
-- if current network is empty, print a warning
if not net:is_floating() and net:is_empty() then
st.template = "cbi/dvalue"
st.network = nil
st.value = translate("There is no device assigned yet, please attach a network device in the \"Physical Settings\" tab")
else
st.template = "admin_network/iface_status"
st.network = arg[1]
st.value = nil
end
end
m.on_init = set_status
m.on_after_save = set_status
l = s:taboption("general", Value, "label", translate("Label"))
l.rmempty = true
l:depends("multipath", "on")
l:depends("multipath", "master")
l:depends("multipath", "backup")
l:depends("multipath", "handover")
p = s:taboption("general", ListValue, "proto", translate("Protocol"))
p.default = net:proto()
if not net:is_installed() then
p_install = s:taboption("general", Button, "_install")
p_install.title = translate("Protocol support is not installed")
p_install.inputtitle = translate("Install package %q" % net:opkg_package())
p_install.inputstyle = "apply"
p_install:depends("proto", net:proto())
function p_install.write()
return luci.http.redirect(
luci.dispatcher.build_url("admin/system/packages") ..
"?submit=1&install=%s" % net:opkg_package()
)
end
end
p_switch = s:taboption("general", Button, "_switch")
p_switch.title = translate("Really switch protocol?")
p_switch.inputtitle = translate("Switch protocol")
p_switch.inputstyle = "apply"
local _, pr
for _, pr in ipairs(nw:get_protocols()) do
p:value(pr:proto(), pr:get_i18n())
if pr:proto() ~= net:proto() then
p_switch:depends("proto", pr:proto())
end
end
auto = s:taboption("advanced", Flag, "auto", translate("Bring up on boot"))
auto.default = (net:proto() == "none") and auto.disabled or auto.enabled
-- Add MPTCP
if fs.access("/proc/sys/net/mptcp") then
mptcp = s:taboption("advanced", ListValue, "multipath", translate("Multipath TCP"), translate("One interface must be set as master"))
mptcp:value("on", translate("enabled"))
mptcp:value("off", translate("disabled"))
mptcp:value("master", translate("master"))
mptcp:value("backup", translate("backup"))
mptcp:value("handover", translate("handover"))
mptcp.default = "off"
end
delegate = s:taboption("advanced", Flag, "delegate", translate("Use builtin IPv6-management"))
delegate.default = delegate.enabled
force_link = s:taboption("advanced", Flag, "force_link",
translate("Force link"),
translate("Set interface properties regardless of the link carrier (If set, carrier sense events do not invoke hotplug handlers)."))
force_link.default = (net:proto() == "static") and force_link.enabled or force_link.disabled
if not net:is_virtual() then
--br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
--br.enabled = "bridge"
--br.rmempty = true
--br:depends("proto", "static")
--br:depends("proto", "dhcp")
--br:depends("proto", "none")
iftype = s:taboption("physical", ListValue, "type", translate("Type of the interface"))
iftype:value("", translate("Default"))
iftype:value("macvlan", translate("Create a macvlan sub interface"))
iftype:value("bridge", translate("Create a bridge over multiple interfaces"))
iftype:depends("proto", "static")
iftype:depends("proto", "dhcp")
iftype:depends("proto", "none")
stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
translate("Enables the Spanning Tree Protocol on this bridge"))
stp:depends("type", "bridge")
stp.rmempty = true
igmp = s:taboption("physical", Flag, "igmp_snooping", translate("Enable <abbr title=\"Internet Group Management Protocol\">IGMP</abbr> snooping"),
translate("Enables IGMP snooping on this bridge"))
igmp:depends("type", "bridge")
igmp.rmempty = true
-- macsource = s:taboption("physical", DynamicList, "vlanmacs", translate("Add MACs address to enable source mode"))
-- macsource:depends("type", "macvlan")
-- macsource.rmempty = true
end
macvlanmaster = s:taboption("physical", Value, "masterintf", translate("Master interface"))
macvlanmaster.default = "eth0"
macvlanmaster:depends("type", "macvlan")
if not net:is_floating() then
ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
ifname_single.template = "cbi/network_ifacelist"
ifname_single.widget = "radio"
ifname_single.nobridges = true
ifname_single.noaliases = false
ifname_single.rmempty = false
ifname_single.network = arg[1]
ifname_single:depends("type", "")
function ifname_single.cfgvalue(self, s)
-- let the template figure out the related ifaces through the network model
return nil
end
function ifname_single.write(self, s, val)
local _, i
local new_ifs = { }
local old_ifs = { }
local alias = net:is_alias()
if alias then
old_ifs[1] = '@' .. alias
else
for _, i in ipairs(net:get_interfaces() or { net:get_interface() }) do
old_ifs[#old_ifs+1] = i:name()
end
end
for i in ut.imatch(val) do
new_ifs[#new_ifs+1] = i
-- if this is not a bridge, only assign first interface
if self.option == "ifname_single" then
break
end
end
table.sort(old_ifs)
table.sort(new_ifs)
for i = 1, math.max(#old_ifs, #new_ifs) do
if old_ifs[i] ~= new_ifs[i] then
backup_ifnames()
for i = 1, #old_ifs do
net:del_interface(old_ifs[i])
end
for i = 1, #new_ifs do
net:add_interface(new_ifs[i])
end
break
end
end
end
end
if not net:is_virtual() then
ifname_multi = s:taboption("physical", Value, "ifname_multi", translate("Interface"))
ifname_multi.template = "cbi/network_ifacelist"
ifname_multi.nobridges = true
ifname_multi.noaliases = true
ifname_multi.rmempty = false
ifname_multi.network = arg[1]
ifname_multi.widget = "checkbox"
ifname_multi:depends("type", "bridge")
ifname_multi.cfgvalue = ifname_single.cfgvalue
ifname_multi.write = ifname_single.write
end
if has_firewall then
fwzone = s:taboption("firewall", Value, "_fwzone",
translate("Create / Assign firewall-zone"),
translate("Choose the firewall zone you want to assign to this interface. Select <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>create</em> field to define a new zone and attach the interface to it."))
fwzone.template = "cbi/firewall_zonelist"
fwzone.network = arg[1]
function fwzone.cfgvalue(self, section)
self.iface = section
local z = fw:get_zone_by_network(section)
return z and z:name()
end
function fwzone.write(self, section, value)
local zone = fw:get_zone(value) or fw:add_zone(value)
if zone then
fw:del_network(section)
zone:add_network(section)
end
end
function fwzone.remove(self, section)
fw:del_network(section)
end
end
function p.write() end
function p.remove() end
function p.validate(self, value, section)
if value == net:proto() then
if not net:is_floating() and net:is_empty() then
local ifn = ((br and (br:formvalue(section) == "bridge"))
and ifname_multi:formvalue(section)
or ifname_single:formvalue(section))
for ifn in ut.imatch(ifn) do
return value
end
return nil, translate("The selected protocol needs a device assigned")
end
end
return value
end
local form, ferr = loadfile(
ut.libpath() .. "/model/cbi/admin_network/proto_%s.lua" % net:proto()
)
if not form then
s:taboption("general", DummyValue, "_error",
translate("Missing protocol extension for proto %q" % net:proto())
).value = ferr
else
setfenv(form, getfenv(1))(m, s, net)
end
local _, field
for _, field in ipairs(s.children) do
if field ~= st and field ~= p and field ~= p_install and field ~= p_switch then
if next(field.deps) then
local _, dep
for _, dep in ipairs(field.deps) do
dep.proto = net:proto()
end
else
field:depends("proto", net:proto())
end
end
end
--
-- Display DNS settings if dnsmasq is available
--
if has_dnsmasq and net:proto() == "static" then
m2 = Map("dhcp", "", "")
local has_section = false
m2.uci:foreach("dhcp", "dhcp", function(s)
if s.interface == arg[1] then
has_section = true
return false
end
end)
if not has_section and has_dnsmasq then
s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
s.anonymous = true
s.cfgsections = function() return { "_enable" } end
x = s:option(Button, "_enable")
x.title = translate("No DHCP Server configured for this interface")
x.inputtitle = translate("Setup DHCP Server")
x.inputstyle = "apply"
elseif has_section then
s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
s.addremove = false
s.anonymous = true
s:tab("general", translate("General Setup"))
s:tab("advanced", translate("Advanced Settings"))
s:tab("ipv6", translate("IPv6 Settings"))
function s.filter(self, section)
return m2.uci:get("dhcp", section, "interface") == arg[1]
end
local ignore = s:taboption("general", Flag, "ignore",
translate("Ignore interface"),
translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
"this interface."))
local start = s:taboption("general", Value, "start", translate("Start"),
translate("Lowest leased address as offset from the network address."))
start.optional = true
start.datatype = "or(uinteger,ip4addr)"
start.default = "100"
local limit = s:taboption("general", Value, "limit", translate("Limit"),
translate("Maximum number of leased addresses."))
limit.optional = true
limit.datatype = "uinteger"
limit.default = "150"
local ltime = s:taboption("general", Value, "leasetime", translate("Lease time"),
translate("Expiry time of leased addresses, minimum is 2 minutes (<code>2m</code>)."))
ltime.rmempty = true
ltime.default = "12h"
local dd = s:taboption("advanced", Flag, "dynamicdhcp",
translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
"clients having static leases will be served."))
dd.default = dd.enabled
s:taboption("advanced", Flag, "force", translate("Force"),
translate("Force DHCP on this network even if another server is detected."))
-- XXX: is this actually useful?
--s:taboption("advanced", Value, "name", translate("Name"),
-- translate("Define a name for this network."))
mask = s:taboption("advanced", Value, "netmask",
translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
translate("Override the netmask sent to clients. Normally it is calculated " ..
"from the subnet that is served."))
mask.optional = true
mask.datatype = "ip4addr"
s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
"192.168.2.2</code>\" which advertises different DNS servers to clients."))
for i, n in ipairs(s.children) do
if n ~= ignore then
n:depends("ignore", "")
end
end
o = s:taboption("ipv6", ListValue, "ra", translate("Router Advertisement-Service"))
o:value("", translate("disabled"))
o:value("server", translate("server mode"))
o:value("relay", translate("relay mode"))
o:value("hybrid", translate("hybrid mode"))
o = s:taboption("ipv6", ListValue, "dhcpv6", translate("DHCPv6-Service"))
o:value("", translate("disabled"))
o:value("server", translate("server mode"))
o:value("relay", translate("relay mode"))
o:value("hybrid", translate("hybrid mode"))
o = s:taboption("ipv6", ListValue, "ndp", translate("NDP-Proxy"))
o:value("", translate("disabled"))
o:value("relay", translate("relay mode"))
o:value("hybrid", translate("hybrid mode"))
o = s:taboption("ipv6", ListValue, "ra_management", translate("DHCPv6-Mode"),
translate("Default is stateless + stateful"))
o:value("0", translate("stateless"))
o:value("1", translate("stateless + stateful"))
o:value("2", translate("stateful-only"))
o:depends("dhcpv6", "server")
o:depends("dhcpv6", "hybrid")
o.default = "1"
o = s:taboption("ipv6", Flag, "ra_default", translate("Always announce default router"),
translate("Announce as default router even if no public prefix is available."))
o:depends("ra", "server")
o:depends("ra", "hybrid")
s:taboption("ipv6", DynamicList, "dns", translate("Announced DNS servers"))
s:taboption("ipv6", DynamicList, "domain", translate("Announced DNS domains"))
else
m2 = nil
end
end
return m, m2

View file

@ -1,298 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local tpl = require "luci.template"
local ntm = require "luci.model.network".init()
local fwm = require "luci.model.firewall".init()
local json = require "luci.jsonc"
local sys = require "luci.sys"
m = Map("network", translate("Interfaces"))
m:chain("wireless")
m:chain("firewall")
m:chain("dhcp")
m.pageaction = false
local tpl_networks = tpl.Template(nil, [[
<div class="cbi-section-node">
<div class="table">
<%
for i, net in ipairs(netlist) do
local z = net[3]
local c = z and z:get_color() or "#EEEEEE"
local t = z and translate("Part of zone %q" % z:name()) or translate("No zone assigned")
local disabled = (net[4]:get("auto") == "0")
local dynamic = net[4]:is_dynamic()
%>
<div class="tr cbi-rowstyle-<%=i % 2 + 1%>">
<div class="td col-3 center middle">
<div class="ifacebox">
<div class="ifacebox-head" style="background-color:<%=c%>" title="<%=pcdata(t)%>">
<strong><%=net[1]:upper()%></strong>
</div>
<div class="ifacebox-body" id="<%=net[1]%>-ifc-devices" data-network="<%=net[1]%>">
<img src="<%=resource%>/icons/ethernet_disabled.png" style="width:16px; height:16px" /><br />
<small>?</small>
</div>
</div>
</div>
<div class="td col-5 left middle" id="<%=net[1]%>-ifc-description">
<em><%:Collecting data...%></em>
</div>
<div class="td cbi-section-actions">
<div>
<input type="button" class="cbi-button cbi-button-neutral" onclick="iface_reconnect('<%=net[1]%>')" title="<%:Reconnect this interface%>" value="<%:Restart%>"<%=ifattr(disabled or dynamic, "disabled", "disabled")%> />
<% if disabled then %>
<input type="hidden" name="cbid.network.<%=net[1]%>.__disable__" value="1" />
<input type="submit" name="cbi.apply" class="cbi-button cbi-button-neutral" onclick="this.previousElementSibling.value='0'" title="<%:Reconnect this interface%>" value="<%:Connect%>"<%=ifattr(dynamic, "disabled", "disabled")%> />
<% else %>
<input type="hidden" name="cbid.network.<%=net[1]%>.__disable__" value="0" />
<input type="submit" name="cbi.apply" class="cbi-button cbi-button-neutral" onclick="this.previousElementSibling.value='1'" title="<%:Shutdown this interface%>" value="<%:Stop%>"<%=ifattr(dynamic, "disabled", "disabled")%> />
<% end %>
<input type="button" class="cbi-button cbi-button-action important" onclick="location.href='<%=url("admin/network/network", net[1])%>'" title="<%:Edit this interface%>" value="<%:Edit%>" id="<%=net[1]%>-ifc-edit"<%=ifattr(dynamic, "disabled", "disabled")%> />
<input type="hidden" name="cbid.network.<%=net[1]%>.__delete__" value="" />
<input type="submit" name="cbi.apply" class="cbi-button cbi-button-negative" onclick="iface_delete(event)" value="<%:Delete%>"<%=ifattr(dynamic, "disabled", "disabled")%> />
</div>
</div>
</div>
<% end %>
</div>
</div>
<div class="cbi-section-create">
<input type="button" class="cbi-button cbi-button-add" value="<%:Add new interface...%>" onclick="location.href='<%=url("admin/network/iface_add")%>'" />
</div>
]])
local _, net
local ifaces, netlist = { }, { }
for _, net in ipairs(ntm:get_networks()) do
if net:name() ~= "loopback" then
local zn = net:zonename()
local z = zn and fwm:get_zone(zn) or fwm:get_zone_by_network(net:name())
local w = 1
if net:is_alias() then
w = 2
elseif net:is_dynamic() then
w = 3
end
ifaces[#ifaces+1] = net:name()
netlist[#netlist+1] = {
net:name(), z and z:name() or "-", z, net, w
}
end
end
table.sort(netlist,
function(a, b)
if a[2] ~= b[2] then
return a[2] < b[2]
elseif a[5] ~= b[5] then
return a[5] < b[5]
else
return a[1] < b[1]
end
end)
s = m:section(TypedSection, "interface", translate("Interface Overview"))
function s.sections(self)
local _, net, sl = nil, nil, { }
for _, net in ipairs(netlist) do
sl[#sl+1] = net[1]
end
return sl
end
function s.render(self)
tpl_networks:render({
netlist = netlist
})
end
o = s:option(Value, "__disable__")
function o.cfgvalue(self, sid)
return (m:get(sid, "auto") == "0") and "1" or "0"
end
function o.write(self, sid, value)
if value ~= "1" then
m:set(sid, "auto", "")
else
m:set(sid, "auto", "0")
end
end
o.remove = o.write
o = s:option(Value, "__delete__")
function o.write(self, sid, value)
ntm:del_network(sid)
end
m:section(SimpleSection).template = "admin_network/iface_overview_status"
if fs.access("/etc/init.d/dsl_control") then
local ok, boarddata = pcall(json.parse, fs.readfile("/etc/board.json"))
local modemtype = (ok == true)
and (type(boarddata) == "table")
and (type(boarddata.dsl) == "table")
and (type(boarddata.dsl.modem) == "table")
and boarddata.dsl.modem.type
dsl = m:section(TypedSection, "dsl", translate("DSL"))
dsl.anonymous = true
annex = dsl:option(ListValue, "annex", translate("Annex"))
annex:value("a", translate("Annex A + L + M (all)"))
annex:value("b", translate("Annex B (all)"))
annex:value("j", translate("Annex J (all)"))
annex:value("m", translate("Annex M (all)"))
annex:value("bdmt", translate("Annex B G.992.1"))
annex:value("b2", translate("Annex B G.992.3"))
annex:value("b2p", translate("Annex B G.992.5"))
annex:value("at1", translate("ANSI T1.413"))
annex:value("admt", translate("Annex A G.992.1"))
annex:value("alite", translate("Annex A G.992.2"))
annex:value("a2", translate("Annex A G.992.3"))
annex:value("a2p", translate("Annex A G.992.5"))
annex:value("l", translate("Annex L G.992.3 POTS 1"))
annex:value("m2", translate("Annex M G.992.3"))
annex:value("m2p", translate("Annex M G.992.5"))
tone = dsl:option(ListValue, "tone", translate("Tone"))
tone:value("", translate("auto"))
tone:value("a", translate("A43C + J43 + A43"))
tone:value("av", translate("A43C + J43 + A43 + V43"))
tone:value("b", translate("B43 + B43C"))
tone:value("bv", translate("B43 + B43C + V43"))
if modemtype == "vdsl" then
xfer_mode = dsl:option(ListValue, "xfer_mode", translate("Encapsulation mode"))
xfer_mode:value("", translate("auto"))
xfer_mode:value("atm", translate("ATM (Asynchronous Transfer Mode)"))
xfer_mode:value("ptm", translate("PTM/EFM (Packet Transfer Mode)"))
line_mode = dsl:option(ListValue, "line_mode", translate("DSL line mode"))
line_mode:value("", translate("auto"))
line_mode:value("adsl", translate("ADSL"))
line_mode:value("vdsl", translate("VDSL"))
ds_snr = dsl:option(ListValue, "ds_snr_offset", translate("Downstream SNR offset"))
ds_snr.default = "0"
for i = -100, 100, 5 do
ds_snr:value(i, translatef("%.1f dB", i / 10))
end
end
firmware = dsl:option(Value, "firmware", translate("Firmware File"))
m.pageaction = true
end
-- Show ATM bridge section if we have the capabilities
if fs.access("/usr/sbin/br2684ctl") then
atm = m:section(TypedSection, "atm-bridge", translate("ATM Bridges"),
translate("ATM bridges expose encapsulated ethernet in AAL5 " ..
"connections as virtual Linux network interfaces which can " ..
"be used in conjunction with DHCP or PPP to dial into the " ..
"provider network."))
atm.addremove = true
atm.anonymous = true
atm.create = function(self, section)
local sid = TypedSection.create(self, section)
local max_unit = -1
m.uci:foreach("network", "atm-bridge",
function(s)
local u = tonumber(s.unit)
if u ~= nil and u > max_unit then
max_unit = u
end
end)
m.uci:set("network", sid, "unit", max_unit + 1)
m.uci:set("network", sid, "atmdev", 0)
m.uci:set("network", sid, "encaps", "llc")
m.uci:set("network", sid, "payload", "bridged")
m.uci:set("network", sid, "vci", 35)
m.uci:set("network", sid, "vpi", 8)
return sid
end
atm:tab("general", translate("General Setup"))
atm:tab("advanced", translate("Advanced Settings"))
vci = atm:taboption("general", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
vpi = atm:taboption("general", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
encaps = atm:taboption("general", ListValue, "encaps", translate("Encapsulation mode"))
encaps:value("llc", translate("LLC"))
encaps:value("vc", translate("VC-Mux"))
atmdev = atm:taboption("advanced", Value, "atmdev", translate("ATM device number"))
unit = atm:taboption("advanced", Value, "unit", translate("Bridge unit number"))
payload = atm:taboption("advanced", ListValue, "payload", translate("Forwarding mode"))
payload:value("bridged", translate("bridged"))
payload:value("routed", translate("routed"))
m.pageaction = true
end
local network = require "luci.model.network"
local s = m:section(NamedSection, "globals", "globals", translate("Global network options"))
if network:has_ipv6() then
local o = s:option(Value, "ula_prefix", translate("IPv6 ULA-Prefix"))
o.datatype = "ip6addr"
o.rmempty = true
end
if fs.access("/proc/sys/net/mptcp") then
local uname = nixio.uname()
local mtcp = s:option(ListValue, "multipath", translate("Multipath TCP"))
mtcp:value("enable", translate("enable"))
mtcp:value("disable", translate("disable"))
local mtcpck = s:option(ListValue, "mptcp_checksum", translate("Multipath TCP checksum"))
mtcpck:value(1, translate("enable"))
mtcpck:value(0, translate("disable"))
local mtcppm = s:option(ListValue, "mptcp_path_manager", translate("Multipath TCP path-manager"))
mtcppm:value("default", translate("default"))
mtcppm:value("fullmesh", translate("fullmesh"))
mtcppm:value("ndiffports", translate("ndiffports"))
mtcppm:value("blinder", translate("blinder"))
if uname.release:sub(1,4) == "4.19" then
mtcppm:value("netlink", translate("Netlink"))
end
local mtcpsch = s:option(ListValue, "mptcp_scheduler", translate("Multipath TCP scheduler"))
mtcpsch:value("default", translate("default"))
mtcpsch:value("roundrobin", translate("round-robin"))
mtcpsch:value("redundant", translate("redundant"))
if uname.release:sub(1,4) == "4.19" then
mtcpsch:value("blest", translate("BLEST"))
end
local mtcpsyn = s:option(Value, "mptcp_syn_retries", translate("Multipath TCP SYN retries"))
mtcpsyn.datatype = "uinteger"
mtcpsyn.rmempty = false
local congestion = s:option(ListValue, "congestion", translate("Congestion Control"))
local availablecong = sys.exec("sysctl net.ipv4.tcp_available_congestion_control | awk -F'= ' '{print $NF}'")
for cong in string.gmatch(availablecong, "[^%s]+") do
congestion:value(cong, translate(cong))
end
end
m.pageaction = true
return m

View file

@ -1,67 +0,0 @@
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local map, section, net = ...
local device, apn, service, pincode, username, password
local ipv6, maxwait, defaultroute, metric, peerdns, dns,
keepalive_failure, keepalive_interval, demand
mca = s:taboption("ahcp", Value, "multicast_address", translate("Multicast address"))
mca.optional = true
mca.placeholder = "ff02::cca6:c0f9:e182:5359"
mca.datatype = "ip6addr"
mca:depends("proto", "ahcp")
port = s:taboption("ahcp", Value, "port", translate("Port"))
port.optional = true
port.placeholder = 5359
port.datatype = "port"
port:depends("proto", "ahcp")
fam = s:taboption("ahcp", ListValue, "_family", translate("Protocol family"))
fam:value("", translate("IPv4 and IPv6"))
fam:value("ipv4", translate("IPv4 only"))
fam:value("ipv6", translate("IPv6 only"))
fam:depends("proto", "ahcp")
function fam.cfgvalue(self, section)
local v4 = m.uci:get_bool("network", section, "ipv4_only")
local v6 = m.uci:get_bool("network", section, "ipv6_only")
if v4 then
return "ipv4"
elseif v6 then
return "ipv6"
end
return ""
end
function fam.write(self, section, value)
if value == "ipv4" then
m.uci:set("network", section, "ipv4_only", "true")
m.uci:delete("network", section, "ipv6_only")
elseif value == "ipv6" then
m.uci:set("network", section, "ipv6_only", "true")
m.uci:delete("network", section, "ipv4_only")
end
end
function fam.remove(self, section)
m.uci:delete("network", section, "ipv4_only")
m.uci:delete("network", section, "ipv6_only")
end
nodns = s:taboption("ahcp", Flag, "no_dns", translate("Disable DNS setup"))
nodns.optional = true
nodns.enabled = "true"
nodns.disabled = "false"
nodns.default = nodns.disabled
nodns:depends("proto", "ahcp")
ltime = s:taboption("ahcp", Value, "lease_time", translate("Lease validity time"))
ltime.optional = true
ltime.placeholder = 3666
ltime.datatype = "uinteger"
ltime:depends("proto", "ahcp")

View file

@ -1,110 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
local wa = require "luci.tools.webadmin"
local fs = require "nixio.fs"
m = Map("network",
translate("Routes"),
translate("Routes specify over which interface and gateway a certain host or network " ..
"can be reached."))
s = m:section(TypedSection, "route", translate("Static IPv4 Routes"))
s.addremove = true
s.anonymous = true
s.template = "cbi/tblsection"
iface = s:option(ListValue, "interface", translate("Interface"))
wa.cbi_add_networks(iface)
t = s:option(Value, "target", translate("Target"), translate("Host-<abbr title=\"Internet Protocol Address\">IP</abbr> or Network"))
t.datatype = "ip4addr"
t.rmempty = false
n = s:option(Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"), translate("if target is a network"))
n.placeholder = "255.255.255.255"
n.datatype = "ip4addr"
n.rmempty = true
g = s:option(Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
g.datatype = "ip4addr"
g.rmempty = true
metric = s:option(Value, "metric", translate("Metric"))
metric.placeholder = 0
metric.datatype = "range(0,255)"
metric.size = 5
metric.rmempty = true
mtu = s:option(Value, "mtu", translate("MTU"))
mtu.placeholder = 1500
mtu.datatype = "range(64,9000)"
mtu.size = 5
mtu.rmempty = true
table = s:option(Value, "table", translate("Table"))
table.rmempty = true
table.size = 5
routetype = s:option(Value, "type", translate("Route type"))
routetype:value("", "unicast")
routetype:value("local", "local")
routetype:value("broadcast", "broadcast")
routetype:value("multicast", "multicast")
routetype:value("unreachable", "unreachable")
routetype:value("prohibit", "prohibit")
routetype:value("blackhole", "blackhole")
routetype:value("anycast", "anycast")
routetype.default = ""
routetype.rmempty = true
if fs.access("/proc/net/ipv6_route") then
s = m:section(TypedSection, "route6", translate("Static IPv6 Routes"))
s.addremove = true
s.anonymous = true
s.template = "cbi/tblsection"
iface = s:option(ListValue, "interface", translate("Interface"))
wa.cbi_add_networks(iface)
t = s:option(Value, "target", translate("Target"), translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Address or Network (CIDR)"))
t.datatype = "ip6addr"
t.rmempty = false
g = s:option(Value, "gateway", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
g.datatype = "ip6addr"
g.rmempty = true
metric = s:option(Value, "metric", translate("Metric"))
metric.placeholder = 0
metric.datatype = "range(0,65535)" -- XXX: not sure
metric.size = 5
metric.rmempty = true
mtu = s:option(Value, "mtu", translate("MTU"))
mtu.placeholder = 1500
mtu.datatype = "range(64,9000)"
mtu.size = 5
mtu.rmempty = true
table = s:option(Value, "table", translate("Table"))
table.rmempty = true
table.size = 5
routetype = s:option(Value, "type", translate("Route type"))
routetype:value("", "unicast")
routetype:value("local", "local")
routetype:value("broadcast", "broadcast")
routetype:value("multicast", "multicast")
routetype:value("unreachable", "unreachable")
routetype:value("prohibit", "prohibit")
routetype:value("blackhole", "blackhole")
routetype:value("anycast", "anycast")
routetype.default = ""
routetype.rmempty = true
end
return m

View file

@ -1,364 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2010-2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
m = Map("network", translate("Switch"), translate("The network ports on this device can be combined to several <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s in which computers can communicate directly with each other. <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network."))
local fs = require "nixio.fs"
local ut = require "luci.util"
local nw = require "luci.model.network"
local switches = { }
nw.init(m.uci)
local topologies = nw:get_switch_topologies() or {}
local update_interfaces = function(old_ifname, new_ifname)
local info = { }
m.uci:foreach("network", "interface", function(section)
local old_ifnames = m.uci:get("network", section[".name"], "ifname")
local new_ifnames = { }
local cur_ifname
local changed = false
for cur_ifname in luci.util.imatch(old_ifnames) do
if cur_ifname == old_ifname then
new_ifnames[#new_ifnames+1] = new_ifname
changed = true
else
new_ifnames[#new_ifnames+1] = cur_ifname
end
end
if changed then
m.uci:set("network", section[".name"], "ifname", table.concat(new_ifnames, " "))
info[#info+1] = translatef("Interface %q device auto-migrated from %q to %q.",
section[".name"], old_ifname, new_ifname)
end
end)
if #info > 0 then
m.message = (m.message and m.message .. "\n" or "") .. table.concat(info, "\n")
end
end
m.uci:foreach("network", "switch",
function(x)
local sid = x['.name']
local switch_name = x.name or sid
local has_vlan = nil
local has_learn = nil
local has_vlan4k = nil
local has_jumbo3 = nil
local has_mirror = nil
local min_vid = 0
local max_vid = 16
local num_vlans = 16
local switch_title
local enable_vlan4k = false
local topo = topologies[switch_name]
if not topo then
m.message = translatef("Switch %q has an unknown topology - the VLAN settings might not be accurate.", switch_name)
topo = {
ports = {
{ num = 0, label = "Port 1" },
{ num = 1, label = "Port 2" },
{ num = 2, label = "Port 3" },
{ num = 3, label = "Port 4" },
{ num = 4, label = "Port 5" },
{ num = 5, label = "CPU (eth0)", tagged = false }
}
}
end
-- Parse some common switch properties from swconfig help output.
local swc = io.popen("swconfig dev %s help 2>/dev/null" % ut.shellquote(switch_name))
if swc then
local is_port_attr = false
local is_vlan_attr = false
while true do
local line = swc:read("*l")
if not line then break end
if line:match("^%s+%-%-vlan") then
is_vlan_attr = true
elseif line:match("^%s+%-%-port") then
is_vlan_attr = false
is_port_attr = true
elseif line:match("cpu @") then
switch_title = line:match("^switch%d: %w+%((.-)%)")
num_vlans = tonumber(line:match("vlans: (%d+)")) or 16
min_vid = 1
elseif line:match(": pvid") or line:match(": tag") or line:match(": vid") then
if is_vlan_attr then has_vlan4k = line:match(": (%w+)") end
elseif line:match(": enable_vlan4k") then
enable_vlan4k = true
elseif line:match(": enable_vlan") then
has_vlan = "enable_vlan"
elseif line:match(": enable_learning") then
has_learn = "enable_learning"
elseif line:match(": enable_mirror_rx") then
has_mirror = "enable_mirror_rx"
elseif line:match(": max_length") then
has_jumbo3 = "max_length"
end
end
swc:close()
end
-- Switch properties
s = m:section(NamedSection, x['.name'], "switch",
switch_title and translatef("Switch %q (%s)", switch_name, switch_title)
or translatef("Switch %q", switch_name))
s.addremove = false
if has_vlan then
s:option(Flag, has_vlan, translate("Enable VLAN functionality"))
end
if has_learn then
x = s:option(Flag, has_learn, translate("Enable learning and aging"))
x.default = x.enabled
end
if has_jumbo3 then
x = s:option(Flag, has_jumbo3, translate("Enable Jumbo Frame passthrough"))
x.enabled = "3"
x.rmempty = true
end
-- Does this switch support port mirroring?
if has_mirror then
s:option(Flag, "enable_mirror_rx", translate("Enable mirroring of incoming packets"))
s:option(Flag, "enable_mirror_tx", translate("Enable mirroring of outgoing packets"))
local sp = s:option(ListValue, "mirror_source_port", translate("Mirror source port"))
local mp = s:option(ListValue, "mirror_monitor_port", translate("Mirror monitor port"))
sp:depends("enable_mirror_tx", "1")
sp:depends("enable_mirror_rx", "1")
mp:depends("enable_mirror_tx", "1")
mp:depends("enable_mirror_rx", "1")
local _, pt
for _, pt in ipairs(topo.ports) do
sp:value(pt.num, pt.label)
mp:value(pt.num, pt.label)
end
end
-- VLAN table
s = m:section(TypedSection, "switch_vlan",
switch_title and translatef("VLANs on %q (%s)", switch_name, switch_title)
or translatef("VLANs on %q", switch_name))
s.template = "cbi/tblsection"
s.addremove = true
s.anonymous = true
-- Filter by switch
s.filter = function(self, section)
local device = m:get(section, "device")
return (device and device == switch_name)
end
-- Override cfgsections callback to enforce row ordering by vlan id.
s.cfgsections = function(self)
local osections = TypedSection.cfgsections(self)
local sections = { }
local section
for _, section in luci.util.spairs(
osections,
function(a, b)
return (tonumber(m:get(osections[a], has_vlan4k or "vlan")) or 9999)
< (tonumber(m:get(osections[b], has_vlan4k or "vlan")) or 9999)
end
) do
sections[#sections+1] = section
end
return sections
end
-- When creating a new vlan, preset it with the highest found vid + 1.
s.create = function(self, section, origin)
-- Filter by switch
if m:get(origin, "device") ~= switch_name then
return
end
local sid = TypedSection.create(self, section)
local max_nr = 0
local max_id = 0
m.uci:foreach("network", "switch_vlan",
function(s)
if s.device == switch_name then
local nr = tonumber(s.vlan)
local id = has_vlan4k and tonumber(s[has_vlan4k])
if nr ~= nil and nr > max_nr then max_nr = nr end
if id ~= nil and id > max_id then max_id = id end
end
end)
m:set(sid, "device", switch_name)
m:set(sid, "vlan", max_nr + 1)
if has_vlan4k then
m:set(sid, has_vlan4k, max_id + 1)
end
return sid
end
local port_opts = { }
local untagged = { }
-- Parse current tagging state from the "ports" option.
local portvalue = function(self, section)
local pt
for pt in (m:get(section, "ports") or ""):gmatch("%w+") do
local pc, tu = pt:match("^(%d+)([tu]*)")
if pc == self.option then return (#tu > 0) and tu or "u" end
end
return ""
end
-- Validate port tagging. Ensure that a port is only untagged once,
-- bail out if not.
local portvalidate = function(self, value, section)
-- ensure that the ports appears untagged only once
if value == "u" then
if not untagged[self.option] then
untagged[self.option] = true
else
return nil,
translatef("%s is untagged in multiple VLANs!", self.title)
end
end
return value
end
local vid = s:option(Value, has_vlan4k or "vlan", "VLAN ID")
local mx_vid = has_vlan4k and 4094 or (num_vlans - 1)
vid.rmempty = false
vid.forcewrite = true
vid.vlan_used = { }
vid.datatype = "and(uinteger,range("..min_vid..","..mx_vid.."))"
-- Validate user provided VLAN ID, make sure its within the bounds
-- allowed by the switch.
vid.validate = function(self, value, section)
local v = tonumber(value)
local m = has_vlan4k and 4094 or (num_vlans - 1)
if v ~= nil and v >= min_vid and v <= m then
if not self.vlan_used[v] then
self.vlan_used[v] = true
return value
else
return nil,
translatef("Invalid VLAN ID given! Only unique IDs are allowed")
end
else
return nil,
translatef("Invalid VLAN ID given! Only IDs between %d and %d are allowed.", min_vid, m)
end
end
-- When writing the "vid" or "vlan" option, serialize the port states
-- as well and write them as "ports" option to uci.
vid.write = function(self, section, new_vid)
local o
local p = { }
for _, o in ipairs(port_opts) do
local new_tag = o:formvalue(section)
if new_tag == "t" then
p[#p+1] = o.option .. new_tag
elseif new_tag == "u" then
p[#p+1] = o.option
end
if o.info and o.info.device then
local old_tag = o:cfgvalue(section)
local old_vid = self:cfgvalue(section)
if old_tag ~= new_tag or old_vid ~= new_vid then
local old_ifname = (old_tag == "u") and o.info.device
or "%s.%s" %{ o.info.device, old_vid }
local new_ifname = (new_tag == "u") and o.info.device
or "%s.%s" %{ o.info.device, new_vid }
if old_ifname ~= new_ifname then
update_interfaces(old_ifname, new_ifname)
end
end
end
end
if enable_vlan4k then
m:set(sid, "enable_vlan4k", "1")
end
m:set(section, "ports", table.concat(p, " "))
return Value.write(self, section, new_vid)
end
-- Fallback to "vlan" option if "vid" option is supported but unset.
vid.cfgvalue = function(self, section)
return m:get(section, has_vlan4k or "vlan")
or m:get(section, "vlan")
end
local _, pt
for _, pt in ipairs(topo.ports) do
local po = s:option(ListValue, tostring(pt.num), pt.label)
po:value("", translate("off"))
if not pt.tagged then
po:value("u", translate("untagged"))
end
po:value("t", translate("tagged"))
po.cfgvalue = portvalue
po.validate = portvalidate
po.write = function() end
po.info = pt
port_opts[#port_opts+1] = po
end
table.sort(port_opts, function(a, b) return a.option < b.option end)
switches[#switches+1] = switch_name
end
)
-- Switch status template
s = m:section(SimpleSection)
s.template = "admin_network/switch_status"
s.switches = switches
return m

File diff suppressed because it is too large Load diff

View file

@ -1,168 +0,0 @@
-- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local nw = require "luci.model.network"
local fw = require "luci.model.firewall"
local uci = require "luci.model.uci".cursor()
local http = require "luci.http"
local iw = luci.sys.wifi.getiwinfo(http.formvalue("device"))
local has_firewall = fs.access("/etc/config/firewall")
if not iw then
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
return
end
m = SimpleForm("network", translatef("Joining Network: %q", http.formvalue("join")))
m.cancel = translate("Back to scan results")
m.reset = false
function m.on_cancel()
local dev = http.formvalue("device")
http.redirect(luci.dispatcher.build_url(
dev and "admin/network/wireless_join?device=" .. dev
or "admin/network/wireless"
))
end
nw.init(uci)
fw.init(uci)
m.hidden = {
device = http.formvalue("device"),
join = http.formvalue("join"),
channel = http.formvalue("channel"),
mode = http.formvalue("mode"),
bssid = http.formvalue("bssid"),
wep = http.formvalue("wep"),
wpa_suites = http.formvalue("wpa_suites"),
wpa_version = http.formvalue("wpa_version")
}
if iw and iw.mbssid_support then
replace = m:field(Flag, "replace", translate("Replace wireless configuration"),
translate("Check this option to delete the existing networks from this radio."))
function replace.cfgvalue() return "0" end
else
replace = m:field(DummyValue, "replace", translate("Replace wireless configuration"))
replace.default = translate("The hardware is not multi-SSID capable and the existing " ..
"configuration will be replaced if you proceed.")
function replace.formvalue() return "1" end
end
if http.formvalue("wep") == "1" then
key = m:field(Value, "key", translate("WEP passphrase"),
translate("Specify the secret encryption key here."))
key.password = true
key.datatype = "wepkey"
elseif (tonumber(m.hidden.wpa_version) or 0) > 0 and
(m.hidden.wpa_suites == "PSK" or m.hidden.wpa_suites == "PSK2")
then
key = m:field(Value, "key", translate("WPA passphrase"),
translate("Specify the secret encryption key here."))
key.password = true
key.datatype = "wpakey"
--m.hidden.wpa_suite = (tonumber(http.formvalue("wpa_version")) or 0) >= 2 and "psk2" or "psk"
end
newnet = m:field(Value, "_netname_new", translate("Name of the new network"),
translate("The allowed characters are: <code>A-Z</code>, <code>a-z</code>, " ..
"<code>0-9</code> and <code>_</code>"
))
newnet.default = m.hidden.mode == "Ad-Hoc" and "mesh" or "wwan"
newnet.datatype = "uciname"
if has_firewall then
fwzone = m:field(Value, "_fwzone",
translate("Create / Assign firewall-zone"),
translate("Choose the firewall zone you want to assign to this interface. Select <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>create</em> field to define a new zone and attach the interface to it."))
fwzone.template = "cbi/firewall_zonelist"
fwzone.default = m.hidden.mode == "Ad-Hoc" and "mesh" or "wan"
end
function newnet.parse(self, section)
local net, zone
if has_firewall then
local value = fwzone:formvalue(section)
if value and #value > 0 then
zone = fw:get_zone(value) or fw:add_zone(value)
end
end
local wdev = nw:get_wifidev(m.hidden.device)
wdev:set("disabled", false)
wdev:set("channel", m.hidden.channel)
if replace:formvalue(section) then
local n
for _, n in ipairs(wdev:get_wifinets()) do
wdev:del_wifinet(n)
end
end
local wconf = {
device = m.hidden.device,
ssid = m.hidden.join,
mode = (m.hidden.mode == "Ad-Hoc" and "adhoc" or "sta")
}
if m.hidden.wep == "1" then
wconf.encryption = "wep-open"
wconf.key = "1"
wconf.key1 = key and key:formvalue(section) or ""
elseif (tonumber(m.hidden.wpa_version) or 0) > 0 then
wconf.encryption = (tonumber(m.hidden.wpa_version) or 0) >= 2 and "psk2" or "psk"
wconf.key = key and key:formvalue(section) or ""
else
wconf.encryption = "none"
end
if wconf.mode == "adhoc" or wconf.mode == "sta" then
wconf.bssid = m.hidden.bssid
end
local value = self:formvalue(section)
net = nw:add_network(value, { proto = "dhcp" })
if not net then
self.error = { [section] = "missing" }
else
wconf.network = net:name()
local wnet = wdev:add_wifinet(wconf)
if wnet then
if zone then
fw:del_network(net:name())
zone:add_network(net:name())
end
uci:save("wireless")
uci:save("network")
uci:save("firewall")
luci.http.redirect(wnet:adminlink())
end
end
end
if has_firewall then
function fwzone.cfgvalue(self, section)
self.iface = section
local z = fw:get_zone_by_network(section)
return z and z:name()
end
end
return m

View file

@ -1,223 +0,0 @@
-- Copyright 2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local utl = require "luci.util"
local tpl = require "luci.template"
local ntm = require "luci.model.network"
local has_iwinfo = pcall(require, "iwinfo")
function guess_wifi_hw(dev)
local bands = ""
local ifname = dev:name()
local name, idx = ifname:match("^([a-z]+)(%d+)")
idx = tonumber(idx)
if has_iwinfo then
local bl = dev.iwinfo.hwmodelist
if bl and next(bl) then
if bl.a then bands = bands .. "a" end
if bl.b then bands = bands .. "b" end
if bl.g then bands = bands .. "g" end
if bl.n then bands = bands .. "n" end
if bl.ac then bands = bands .. "ac" end
end
local hw = dev.iwinfo.hardware_name
if hw then
return "%s 802.11%s" %{ hw, bands }
end
end
-- wl.o
if name == "wl" then
local name = translatef("Broadcom 802.11%s Wireless Controller", bands)
local nm = 0
local fd = nixio.open("/proc/bus/pci/devices", "r")
if fd then
local ln
for ln in fd:linesource() do
if ln:match("wl$") then
if nm == idx then
local version = ln:match("^%S+%s+%S%S%S%S([0-9a-f]+)")
name = translatef(
"Broadcom BCM%04x 802.11 Wireless Controller",
tonumber(version, 16)
)
break
else
nm = nm + 1
end
end
end
fd:close()
end
return name
-- dunno yet
else
return translatef("Generic 802.11%s Wireless Controller", bands)
end
end
local tpl_radio = tpl.Template(nil, [[
<div class="cbi-section-node">
<div class="table">
<!-- physical device -->
<div class="tr cbi-rowstyle-2">
<div class="td col-2 center middle">
<span class="ifacebadge"><img src="<%=resource%>/icons/wifi_disabled.png" id="<%=dev:name()%>-iw-upstate" /> <%=dev:name()%></span>
</div>
<div class="td col-7 left middle">
<big><strong><%=hw%></strong></big><br />
<span id="<%=dev:name()%>-iw-devinfo"></span>
</div>
<div class="td middle cbi-section-actions">
<div>
<input type="button" class="cbi-button cbi-button-neutral" title="<%:Restart radio interface%>" value="<%:Restart%>" data-radio="<%=dev:name()%>" onclick="wifi_restart(event)" />
<input type="button" class="cbi-button cbi-button-action important" title="<%:Find and join network%>" value="<%:Scan%>" onclick="cbi_submit(this, 'device', '<%=dev:name()%>', '<%=url('admin/network/wireless_join')%>')" />
<input type="button" class="cbi-button cbi-button-add" title="<%:Provide new network%>" value="<%:Add%>" onclick="cbi_submit(this, 'device', '<%=dev:name()%>', '<%=url('admin/network/wireless_add')%>')" />
</div>
</div>
</div>
<!-- /physical device -->
<!-- network list -->
<% if #wnets > 0 then %>
<% for i, net in ipairs(wnets) do local disabled = (dev:get("disabled") == "1" or net:get("disabled") == "1") %>
<div class="tr cbi-rowstyle-<%=1 + ((i-1) % 2)%>">
<div class="td col-2 center middle" id="<%=net:id()%>-iw-signal">
<span class="ifacebadge" title="<%:Not associated%>"><img src="<%=resource%>/icons/signal-<%= disabled and "none" or "0" %>.png" /> 0%</span>
</div>
<div class="td col-7 left middle" id="<%=net:id()%>-iw-status" data-network="<%=net:id()%>" data-disabled="<%= disabled and "true" or "false" %>">
<em><%= disabled and translate("Wireless is disabled") or translate("Collecting data...") %></em>
</div>
<div class="td middle cbi-section-actions">
<div>
<% if disabled then %>
<input name="cbid.wireless.<%=net:name()%>.__disable__" type="hidden" value="1" />
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-neutral" title="<%:Enable this network%>" value="<%:Enable%>" onclick="this.previousElementSibling.value='0'" />
<% else %>
<input name="cbid.wireless.<%=net:name()%>.__disable__" type="hidden" value="0" />
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-neutral" title="<%:Disable this network%>" value="<%:Disable%>" onclick="this.previousElementSibling.value='1'" />
<% end %>
<input type="button" class="cbi-button cbi-button-action important" onclick="location.href='<%=net:adminlink()%>'" title="<%:Edit this network%>" value="<%:Edit%>" />
<input name="cbid.wireless.<%=net:name()%>.__delete__" type="hidden" value="" />
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-negative" title="<%:Delete this network%>" value="<%:Remove%>" onclick="wifi_delete(event)" />
</div>
</div>
</div>
<% end %>
<% else %>
<div class="tr placeholder">
<div class="td">
<em><%:No network configured on this device%></em>
</div>
</div>
<% end %>
<!-- /network list -->
</div>
</div>
]])
m = Map("wireless", translate("Wireless Overview"))
m:chain("network")
m.pageaction = false
if not has_iwinfo then
s = m:section(NamedSection, "__warning__")
function s.render(self)
tpl.render_string([[
<div class="alert-message warning">
<h4><%:Package libiwinfo required!%></h4>
<p><%_The <em>libiwinfo-lua</em> package is not installed. You must install this component for working wireless configuration!%></p>
</div>
]])
end
end
local _, dev, net
for _, dev in ipairs(ntm:get_wifidevs()) do
s = m:section(TypedSection)
s.wnets = dev:get_wifinets()
function s.render(self, sid)
tpl_radio:render({
hw = guess_wifi_hw(dev),
dev = dev,
wnets = self.wnets
})
end
function s.cfgsections(self)
local _, net, sl = nil, nil, { }
for _, net in ipairs(self.wnets) do
sl[#sl+1] = net:name()
self.wnets[net:name()] = net
end
return sl
end
o = s:option(Value, "__disable__")
function o.cfgvalue(self, sid)
local wnet = self.section.wnets[sid]
local wdev = wnet:get_device()
return ((wnet and wnet:get("disabled") == "1") or
(wdev and wdev:get("disabled") == "1")) and "1" or "0"
end
function o.write(self, sid, value)
local wnet = self.section.wnets[sid]
local wdev = wnet:get_device()
if value ~= "1" then
wnet:set("disabled", nil)
wdev:set("disabled", nil)
else
wnet:set("disabled", "1")
end
end
o.remove = o.write
o = s:option(Value, "__delete__")
function o.write(self, sid, value)
local wnet = self.section.wnets[sid]
local nets = wnet:get_networks()
ntm:del_wifinet(wnet:id())
local _, net
for _, net in ipairs(nets) do
if net:is_empty() then
ntm:del_network(net:name())
end
end
end
end
s = m:section(NamedSection, "__script__")
s.template = "admin_network/wifi_overview_status"
s = m:section(NamedSection, "__assoclist__")
function s.render(self, sid)
tpl.render_string([[
<h2><%:Associated Stations%></h2>
<%+admin_network/wifi_assoclist%>
]])
end
return m

View file

@ -1,34 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
f = SimpleForm("processes", translate("Processes"), translate("This list gives an overview over currently running system processes and their status."))
f.reset = false
f.submit = false
t = f:section(Table, luci.sys.process.list())
t:option(DummyValue, "PID", translate("PID"))
t:option(DummyValue, "USER", translate("Owner"))
t:option(DummyValue, "COMMAND", translate("Command"))
t:option(DummyValue, "%CPU", translate("CPU usage (%)"))
t:option(DummyValue, "%MEM", translate("Memory usage (%)"))
hup = t:option(Button, "_hup", translate("Hang Up"))
hup.inputstyle = "reload"
function hup.write(self, section)
null, self.tag_error[section] = luci.sys.process.signal(section, 1)
end
term = t:option(Button, "_term", translate("Terminate"))
term.inputstyle = "remove"
function term.write(self, section)
null, self.tag_error[section] = luci.sys.process.signal(section, 15)
end
kill = t:option(Button, "_kill", translate("Kill"))
kill.inputstyle = "reset"
function kill.write(self, section)
null, self.tag_error[section] = luci.sys.process.signal(section, 9)
end
return f

View file

@ -1,122 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
m = Map("system", translate("Router Password"),
translate("Changes the administrator password for accessing the device"))
s = m:section(TypedSection, "_dummy", "")
s.addremove = false
s.anonymous = true
pw1 = s:option(Value, "pw1", translate("Password"))
pw1.password = true
pw2 = s:option(Value, "pw2", translate("Confirmation"))
pw2.password = true
function s.cfgsections()
return { "_pass" }
end
function m.parse(map)
local v1 = pw1:formvalue("_pass")
local v2 = pw2:formvalue("_pass")
if v1 and v2 and #v1 > 0 and #v2 > 0 then
if v1 == v2 then
if luci.sys.user.setpasswd(luci.dispatcher.context.authuser, v1) == 0 then
m.message = translate("Password successfully changed!")
else
m.message = translate("Unknown Error, password not changed!")
end
else
m.message = translate("Given password confirmation did not match, password not changed!")
end
end
Map.parse(map)
end
if fs.access("/etc/config/dropbear") then
m2 = Map("dropbear", translate("SSH Access"),
translate("Dropbear offers <abbr title=\"Secure Shell\">SSH</abbr> network shell access and an integrated <abbr title=\"Secure Copy\">SCP</abbr> server"))
s = m2:section(TypedSection, "dropbear", translate("Dropbear Instance"))
s.anonymous = true
s.addremove = true
ni = s:option(Value, "Interface", translate("Interface"),
translate("Listen only on the given interface or, if unspecified, on all"))
ni.template = "cbi/network_netlist"
ni.nocreate = true
ni.unspecified = true
pt = s:option(Value, "Port", translate("Port"),
translate("Specifies the listening port of this <em>Dropbear</em> instance"))
pt.datatype = "port"
pt.default = 22
pa = s:option(Flag, "PasswordAuth", translate("Password authentication"),
translate("Allow <abbr title=\"Secure Shell\">SSH</abbr> password authentication"))
pa.enabled = "on"
pa.disabled = "off"
pa.default = pa.enabled
pa.rmempty = false
ra = s:option(Flag, "RootPasswordAuth", translate("Allow root logins with password"),
translate("Allow the <em>root</em> user to login with password"))
ra.enabled = "on"
ra.disabled = "off"
ra.default = ra.enabled
gp = s:option(Flag, "GatewayPorts", translate("Gateway ports"),
translate("Allow remote hosts to connect to local SSH forwarded ports"))
gp.enabled = "on"
gp.disabled = "off"
gp.default = gp.disabled
s2 = m2:section(TypedSection, "_dummy", translate("SSH-Keys"),
translate("Here you can paste public SSH-Keys (one per line) for SSH public-key authentication."))
s2.addremove = false
s2.anonymous = true
s2.template = "cbi/tblsection"
function s2.cfgsections()
return { "_keys" }
end
keys = s2:option(TextValue, "_data", "")
keys.wrap = "off"
keys.rows = 3
function keys.cfgvalue()
return fs.readfile("/etc/dropbear/authorized_keys") or ""
end
function keys.write(self, section, value)
return fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n"))
end
function keys.remove(self, section, value)
return fs.writefile("/etc/dropbear/authorized_keys", "")
end
end
return m, m2

View file

@ -1,80 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
if luci.http.formvalue("cbid.luci.1._list") then
luci.http.redirect(luci.dispatcher.build_url("admin/system/flashops/backupfiles") .. "?display=list")
elseif luci.http.formvalue("cbid.luci.1._edit") then
luci.http.redirect(luci.dispatcher.build_url("admin/system/flashops/backupfiles") .. "?display=edit")
return
end
m = SimpleForm("luci", translate("Backup file list"))
m:append(Template("admin_system/backupfiles"))
if luci.http.formvalue("display") ~= "list" then
f = m:section(SimpleSection, nil, translate("This is a list of shell glob patterns for matching files and directories to include during sysupgrade. Modified files in /etc/config/ and certain other configurations are automatically preserved."))
l = f:option(Button, "_list", translate("Show current backup file list"))
l.inputtitle = translate("Open list...")
l.inputstyle = "apply"
c = f:option(TextValue, "_custom")
c.rmempty = false
c.cols = 70
c.rows = 30
c.cfgvalue = function(self, section)
return nixio.fs.readfile("/etc/sysupgrade.conf")
end
c.write = function(self, section, value)
value = value:gsub("\r\n?", "\n")
return nixio.fs.writefile("/etc/sysupgrade.conf", value)
end
else
m.submit = false
m.reset = false
f = m:section(SimpleSection, nil, translate("Below is the determined list of files to backup. It consists of changed configuration files marked by opkg, essential base files and the user defined backup patterns."))
l = f:option(Button, "_edit", translate("Back to configuration"))
l.inputtitle = translate("Close list...")
l.inputstyle = "link"
d = f:option(DummyValue, "_detected")
d.rawhtml = true
d.cfgvalue = function(s)
local list = io.popen(
"( find $(sed -ne '/^[[:space:]]*$/d; /^#/d; p' /etc/sysupgrade.conf " ..
"/lib/upgrade/keep.d/* 2>/dev/null) -type f 2>/dev/null; " ..
"opkg list-changed-conffiles ) | sort -u"
)
if list then
local files = { "<ul>" }
while true do
local ln = list:read("*l")
if not ln then
break
else
files[#files+1] = "<li>"
files[#files+1] = luci.util.pcdata(ln)
files[#files+1] = "</li>"
end
end
list:close()
files[#files+1] = "</ul>"
return table.concat(files, "")
end
return "<em>" .. translate("No files found") .. "</em>"
end
end
return m

View file

@ -1,32 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008-2013 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local cronfile = "/etc/crontabs/root"
f = SimpleForm("crontab", translate("Scheduled Tasks"),
translate("This is the system crontab in which scheduled tasks can be defined.") ..
translate("<br/>Note: you need to manually restart the cron service if the " ..
"crontab file was empty before editing."))
t = f:field(TextValue, "crons")
t.rmempty = true
t.rows = 10
function t.cfgvalue()
return fs.readfile(cronfile) or ""
end
function f.handle(self, state, data)
if state == FORM_VALID then
if data.crons then
fs.writefile(cronfile, data.crons:gsub("\r\n", "\n"))
luci.sys.call("/usr/bin/crontab %q" % cronfile)
else
fs.writefile(cronfile, "")
end
end
return true
end
return f

View file

@ -1,270 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
require("luci.tools.webadmin")
local fs = require "nixio.fs"
local util = require "nixio.util"
local tp = require "luci.template.parser"
local block = io.popen("block info", "r")
local ln, dev, devices = nil, nil, {}
repeat
ln = block:read("*l")
dev = ln and ln:match("^/dev/(.-):")
if dev then
local e, s, key, val = { }
for key, val in ln:gmatch([[(%w+)="(.-)"]]) do
e[key:lower()] = val
devices[val] = e
end
s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev)))
e.dev = "/dev/%s" % dev
e.size = s and math.floor(s / 2048)
devices[e.dev] = e
end
until not ln
block:close()
m = Map("fstab", translate("Mount Points"))
s = m:section(TypedSection, "global", translate("Global Settings"))
s.addremove = false
s.anonymous = true
detect = s:option(Button, "block_detect", translate("Generate Config"), translate("Find all currently attached filesystems and swap and replace configuration with defaults based on what was detected"))
detect.inputstyle = "reload"
detect.write = function(self, section)
luci.sys.call("block detect >/etc/config/fstab")
luci.http.redirect(luci.dispatcher.build_url("admin/system", "fstab"))
end
o = s:option(Flag, "anon_swap", translate("Anonymous Swap"), translate("Mount swap not specifically configured"))
o.default = o.disabled
o.rmempty = false
o = s:option(Flag, "anon_mount", translate("Anonymous Mount"), translate("Mount filesystems not specifically configured"))
o.default = o.disabled
o.rmempty = false
o = s:option(Flag, "auto_swap", translate("Automount Swap"), translate("Automatically mount swap on hotplug"))
o.default = o.enabled
o.rmempty = false
o = s:option(Flag, "auto_mount", translate("Automount Filesystem"), translate("Automatically mount filesystems on hotplug"))
o.default = o.enabled
o.rmempty = false
o = s:option(Flag, "check_fs", translate("Check filesystems before mount"), translate("Automatically check filesystem for errors before mounting"))
o.default = o.disabled
o.rmempty = false
local mounts = luci.sys.mounts()
local non_system_mounts = {}
for rawmount, val in pairs(mounts) do
if (string.find(val.mountpoint, "/tmp/.jail") == nil) then
repeat
val.umount = false
if (val.mountpoint == "/") then
break
elseif (val.mountpoint == "/overlay") then
break
elseif (val.mountpoint == "/rom") then
break
elseif (val.mountpoint == "/tmp") then
break
elseif (val.mountpoint == "/tmp/shm") then
break
elseif (val.mountpoint == "/tmp/upgrade") then
break
elseif (val.mountpoint == "/dev") then
break
end
val.umount = true
until true
non_system_mounts[rawmount] = val
end
end
v = m:section(Table, non_system_mounts, translate("Mounted file systems"))
fs = v:option(DummyValue, "fs", translate("Filesystem"))
mp = v:option(DummyValue, "mountpoint", translate("Mount Point"))
avail = v:option(DummyValue, "avail", translate("Available"))
function avail.cfgvalue(self, section)
return luci.tools.webadmin.byte_format(
( tonumber(mounts[section].available) or 0 ) * 1024
) .. " / " .. luci.tools.webadmin.byte_format(
( tonumber(mounts[section].blocks) or 0 ) * 1024
)
end
used = v:option(DummyValue, "used", translate("Used"))
function used.cfgvalue(self, section)
return ( mounts[section].percent or "0%" ) .. " (" ..
luci.tools.webadmin.byte_format(
( tonumber(mounts[section].used) or 0 ) * 1024
) .. ")"
end
unmount = v:option(Button, "unmount", translate("Unmount"))
unmount.render = function(self, section, scope)
if non_system_mounts[section].umount then
self.title = translate("Unmount")
self.inputstyle = "remove"
Button.render(self, section, scope)
end
end
unmount.write = function(self, section)
if non_system_mounts[section].umount then
luci.sys.call("/bin/umount '%s'" % luci.util.shellstartsqescape(non_system_mounts[section].mountpoint))
return luci.http.redirect(luci.dispatcher.build_url("admin/system", "fstab"))
end
end
mount = m:section(TypedSection, "mount", translate("Mount Points"), translate("Mount Points define at which point a memory device will be attached to the filesystem"))
mount.anonymous = true
mount.addremove = true
mount.template = "cbi/tblsection"
mount.extedit = luci.dispatcher.build_url("admin/system/fstab/mount/%s")
mount.create = function(...)
local sid = TypedSection.create(...)
if sid then
luci.http.redirect(mount.extedit % sid)
return
end
end
mount:option(Flag, "enabled", translate("Enabled")).rmempty = false
dev = mount:option(DummyValue, "device", translate("Device"))
dev.rawhtml = true
dev.cfgvalue = function(self, section)
local v, e
v = m.uci:get("fstab", section, "uuid")
e = v and devices[v:lower()]
if v and e and e.size then
return "UUID: %s (%s, %d MB)" %{ tp.pcdata(v), e.dev, e.size }
elseif v and e then
return "UUID: %s (%s)" %{ tp.pcdata(v), e.dev }
elseif v then
return "UUID: %s (<em>%s</em>)" %{ tp.pcdata(v), translate("not present") }
end
v = m.uci:get("fstab", section, "label")
e = v and devices[v]
if v and e and e.size then
return "Label: %s (%s, %d MB)" %{ tp.pcdata(v), e.dev, e.size }
elseif v and e then
return "Label: %s (%s)" %{ tp.pcdata(v), e.dev }
elseif v then
return "Label: %s (<em>%s</em>)" %{ tp.pcdata(v), translate("not present") }
end
v = Value.cfgvalue(self, section) or "?"
e = v and devices[v]
if v and e and e.size then
return "%s (%d MB)" %{ tp.pcdata(v), e.size }
elseif v and e then
return tp.pcdata(v)
elseif v then
return "%s (<em>%s</em>)" %{ tp.pcdata(v), translate("not present") }
end
end
mp = mount:option(DummyValue, "target", translate("Mount Point"))
mp.cfgvalue = function(self, section)
if m.uci:get("fstab", section, "is_rootfs") == "1" then
return "/overlay"
else
return Value.cfgvalue(self, section) or "?"
end
end
fs = mount:option(DummyValue, "fstype", translate("Filesystem"))
fs.cfgvalue = function(self, section)
local v, e
v = m.uci:get("fstab", section, "uuid")
v = v and v:lower() or m.uci:get("fstab", section, "label")
v = v or m.uci:get("fstab", section, "device")
e = v and devices[v]
return e and e.type or m.uci:get("fstab", section, "fstype") or "?"
end
op = mount:option(DummyValue, "options", translate("Options"))
op.cfgvalue = function(self, section)
return Value.cfgvalue(self, section) or "defaults"
end
rf = mount:option(DummyValue, "is_rootfs", translate("Root"))
rf.cfgvalue = function(self, section)
local target = m.uci:get("fstab", section, "target")
if target == "/" then
return translate("yes")
elseif target == "/overlay" then
return translate("overlay")
else
return translate("no")
end
end
ck = mount:option(DummyValue, "enabled_fsck", translate("Check"))
ck.cfgvalue = function(self, section)
return Value.cfgvalue(self, section) == "1"
and translate("yes") or translate("no")
end
swap = m:section(TypedSection, "swap", "SWAP", translate("If your physical memory is insufficient unused data can be temporarily swapped to a swap-device resulting in a higher amount of usable <abbr title=\"Random Access Memory\">RAM</abbr>. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the <abbr title=\"Random Access Memory\">RAM</abbr>."))
swap.anonymous = true
swap.addremove = true
swap.template = "cbi/tblsection"
swap.extedit = luci.dispatcher.build_url("admin/system/fstab/swap/%s")
swap.create = function(...)
local sid = TypedSection.create(...)
if sid then
luci.http.redirect(swap.extedit % sid)
return
end
end
swap:option(Flag, "enabled", translate("Enabled")).rmempty = false
dev = swap:option(DummyValue, "device", translate("Device"))
dev.cfgvalue = function(self, section)
local v
v = m.uci:get("fstab", section, "uuid")
if v then return "UUID: %s" % v end
v = m.uci:get("fstab", section, "label")
if v then return "Label: %s" % v end
v = Value.cfgvalue(self, section) or "?"
e = v and devices[v]
if v and e and e.size then
return "%s (%s MB)" % {v, e.size}
else
return v
end
end
return m

View file

@ -1,151 +0,0 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local util = require "nixio.util"
local has_fscheck = fs.access("/usr/sbin/e2fsck")
local block = io.popen("block info", "r")
local ln, dev, devices = nil, nil, {}
repeat
ln = block:read("*l")
dev = ln and ln:match("^/dev/(.-):")
if dev then
local e, s, key, val = { }
for key, val in ln:gmatch([[(%w+)="(.-)"]]) do
e[key:lower()] = val
end
s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev)))
e.dev = "/dev/%s" % dev
e.size = s and math.floor(s / 2048)
devices[#devices+1] = e
end
until not ln
block:close()
m = Map("fstab", translate("Mount Points - Mount Entry"))
m.redirect = luci.dispatcher.build_url("admin/system/fstab")
if not arg[1] or m.uci:get("fstab", arg[1]) ~= "mount" then
luci.http.redirect(m.redirect)
return
end
mount = m:section(NamedSection, arg[1], "mount", translate("Mount Entry"))
mount.anonymous = true
mount.addremove = false
mount:tab("general", translate("General Settings"))
mount:tab("advanced", translate("Advanced Settings"))
mount:taboption("general", Flag, "enabled", translate("Enable this mount")).rmempty = false
o = mount:taboption("general", Value, "uuid", translate("UUID"),
translate("If specified, mount the device by its UUID instead of a fixed device node"))
o:value("", translate("-- match by uuid --"))
for i, d in ipairs(devices) do
if d.uuid and d.size then
o:value(d.uuid, "%s (%s, %d MB)" %{ d.uuid, d.dev, d.size })
elseif d.uuid then
o:value(d.uuid, "%s (%s)" %{ d.uuid, d.dev })
end
end
o = mount:taboption("general", Value, "label", translate("Label"),
translate("If specified, mount the device by the partition label instead of a fixed device node"))
o:value("", translate("-- match by label --"))
o:depends("uuid", "")
for i, d in ipairs(devices) do
if d.label and d.size then
o:value(d.label, "%s (%s, %d MB)" %{ d.label, d.dev, d.size })
elseif d.label then
o:value(d.label, "%s (%s)" %{ d.label, d.dev })
end
end
o = mount:taboption("general", Value, "device", translate("Device"),
translate("The device file of the memory or partition (<abbr title=\"for example\">e.g.</abbr> <code>/dev/sda1</code>)"))
o:value("", translate("-- match by device --"))
o:depends({ uuid = "", label = "" })
for i, d in ipairs(devices) do
if d.size then
o:value(d.dev, "%s (%d MB)" %{ d.dev, d.size })
else
o:value(d.dev)
end
end
o = mount:taboption("general", Value, "target", translate("Mount point"),
translate("Specifies the directory the device is attached to"))
o:value("/", translate("Use as root filesystem (/)"))
o:value("/overlay", translate("Use as external overlay (/overlay)"))
o = mount:taboption("general", DummyValue, "__notice", translate("Root preparation"))
o:depends("target", "/")
o.rawhtml = true
o.default = [[
<p>%s</p><pre>mkdir -p /tmp/introot
mkdir -p /tmp/extroot
mount --bind / /tmp/introot
mount /dev/sda1 /tmp/extroot
tar -C /tmp/introot -cvf - . | tar -C /tmp/extroot -xf -
umount /tmp/introot
umount /tmp/extroot</pre>
]] %{
translate("Make sure to clone the root filesystem using something like the commands below:"),
}
o = mount:taboption("advanced", Value, "fstype", translate("Filesystem"),
translate("The filesystem that was used to format the memory (<abbr title=\"for example\">e.g.</abbr> <samp><abbr title=\"Third Extended Filesystem\">ext3</abbr></samp>)"))
o:value("", "auto")
local fs
for fs in io.lines("/proc/filesystems") do
fs = fs:match("%S+")
if fs ~= "nodev" then
o:value(fs)
end
end
o = mount:taboption("advanced", Value, "options", translate("Mount options"),
translate("See \"mount\" manpage for details"))
o.placeholder = "defaults"
if has_fscheck then
o = mount:taboption("advanced", Flag, "enabled_fsck", translate("Run filesystem check"),
translate("Run a filesystem check before mounting the device"))
end
return m

View file

@ -1,54 +0,0 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local util = require "nixio.util"
local devices = {}
util.consume((fs.glob("/dev/sd*")), devices)
util.consume((fs.glob("/dev/hd*")), devices)
util.consume((fs.glob("/dev/scd*")), devices)
util.consume((fs.glob("/dev/mmc*")), devices)
local size = {}
for i, dev in ipairs(devices) do
local s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev:sub(6))))
size[dev] = s and math.floor(s / 2048)
end
m = Map("fstab", translate("Mount Points - Swap Entry"))
m.redirect = luci.dispatcher.build_url("admin/system/fstab")
if not arg[1] or m.uci:get("fstab", arg[1]) ~= "swap" then
luci.http.redirect(m.redirect)
return
end
mount = m:section(NamedSection, arg[1], "swap", translate("Swap Entry"))
mount.anonymous = true
mount.addremove = false
mount:tab("general", translate("General Settings"))
mount:tab("advanced", translate("Advanced Settings"))
mount:taboption("general", Flag, "enabled", translate("Enable this swap")).rmempty = false
o = mount:taboption("general", Value, "device", translate("Device"),
translate("The device file of the memory or partition (<abbr title=\"for example\">e.g.</abbr> <code>/dev/sda1</code>)"))
for i, d in ipairs(devices) do
o:value(d, size[d] and "%s (%s MB)" % {d, size[d]})
end
o = mount:taboption("advanced", Value, "uuid", translate("UUID"),
translate("If specified, mount the device by its UUID instead of a fixed device node"))
o = mount:taboption("advanced", Value, "label", translate("Label"),
translate("If specified, mount the device by the partition label instead of a fixed device node"))
return m

View file

@ -1,64 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local ipkgfile = "/etc/opkg.conf"
local distfeeds = "/etc/opkg/distfeeds.conf"
local customfeeds = "/etc/opkg/customfeeds.conf"
f = SimpleForm("ipkgconf", translate("OPKG-Configuration"), translate("General options for opkg"))
f:append(Template("admin_system/ipkg"))
t = f:field(TextValue, "lines")
t.wrap = "off"
t.rows = 10
function t.cfgvalue()
return nixio.fs.readfile(ipkgfile) or ""
end
function t.write(self, section, data)
return nixio.fs.writefile(ipkgfile, data:gsub("\r\n", "\n"))
end
function f.handle(self, state, data)
return true
end
g = SimpleForm("distfeedconf", translate("Distribution feeds"),
translate("Build/distribution specific feed definitions. This file will NOT be preserved in any sysupgrade."))
d = g:field(TextValue, "lines2")
d.wrap = "off"
d.rows = 10
function d.cfgvalue()
return nixio.fs.readfile(distfeeds) or ""
end
function d.write(self, section, data)
return nixio.fs.writefile(distfeeds, data:gsub("\r\n", "\n"))
end
function g.handle(self, state, data)
return true
end
h = SimpleForm("customfeedconf", translate("Custom feeds"),
translate("Custom feed definitions, e.g. private feeds. This file can be preserved in a sysupgrade."))
c = h:field(TextValue, "lines3")
c.wrap = "off"
c.rows = 10
function c.cfgvalue()
return nixio.fs.readfile(customfeeds) or ""
end
function c.write(self, section, data)
return nixio.fs.writefile(customfeeds, data:gsub("\r\n", "\n"))
end
function h.handle(self, state, data)
return true
end
return f, g, h

View file

@ -1,158 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
m = Map("system", translate("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), translate("Customizes the behaviour of the device <abbr title=\"Light Emitting Diode\">LED</abbr>s if possible."))
local sysfs_path = "/sys/class/leds/"
local leds = {}
local fs = require "nixio.fs"
local nu = require "nixio.util"
local util = require "luci.util"
if fs.access(sysfs_path) then
leds = nu.consume((fs.dir(sysfs_path)))
end
if #leds == 0 then
return m
end
s = m:section(TypedSection, "led", "")
s.anonymous = true
s.addremove = true
function s.parse(self, ...)
TypedSection.parse(self, ...)
os.execute("/etc/init.d/led enable")
end
s:option(Value, "name", translate("Name"))
sysfs = s:option(ListValue, "sysfs", translate("<abbr title=\"Light Emitting Diode\">LED</abbr> Name"))
for k, v in ipairs(leds) do
sysfs:value(v)
end
s:option(Flag, "default", translate("Default state")).rmempty = false
trigger = s:option(ListValue, "trigger", translate("Trigger"))
local triggers = fs.readfile(sysfs_path .. leds[1] .. "/trigger")
for t in triggers:gmatch("[%w-]+") do
trigger:value(t, translate(t:gsub("-", "")))
end
delayon = s:option(Value, "delayon", translate ("On-State Delay"))
delayon:depends("trigger", "timer")
delayoff = s:option(Value, "delayoff", translate ("Off-State Delay"))
delayoff:depends("trigger", "timer")
dev = s:option(ListValue, "_net_dev", translate("Device"))
dev.rmempty = true
dev:value("")
dev:depends("trigger", "netdev")
function dev.cfgvalue(self, section)
return m.uci:get("system", section, "dev")
end
function dev.write(self, section, value)
m.uci:set("system", section, "dev", value)
end
function dev.remove(self, section)
local t = trigger:formvalue(section)
if t ~= "netdev" and t ~= "usbdev" then
m.uci:delete("system", section, "dev")
end
end
for k, v in pairs(luci.sys.net.devices()) do
if v ~= "lo" then
dev:value(v)
end
end
mode = s:option(MultiValue, "mode", translate("Trigger Mode"))
mode.rmempty = true
mode:depends("trigger", "netdev")
mode:value("link", translate("Link On"))
mode:value("tx", translate("Transmit"))
mode:value("rx", translate("Receive"))
usbdev = s:option(ListValue, "_usb_dev", translate("USB Device"))
usbdev:depends("trigger", "usbdev")
usbdev.rmempty = true
usbdev:value("")
function usbdev.cfgvalue(self, section)
return m.uci:get("system", section, "dev")
end
function usbdev.write(self, section, value)
m.uci:set("system", section, "dev", value)
end
function usbdev.remove(self, section)
local t = trigger:formvalue(section)
if t ~= "netdev" and t ~= "usbdev" then
m.uci:delete("system", section, "dev")
end
end
usbport = s:option(MultiValue, "port", translate("USB Ports"))
usbport:depends("trigger", "usbport")
usbport.rmempty = true
usbport.widget = "checkbox"
usbport.cast = "table"
usbport.size = 1
function usbport.valuelist(self, section)
local port, ports = nil, {}
for port in util.imatch(m.uci:get("system", section, "port")) do
local b, n = port:match("^usb(%d+)-port(%d+)$")
if not (b and n) then
b, n = port:match("^(%d+)-(%d+)$")
end
if b and n then
ports[#ports+1] = "usb%u-port%u" %{ tonumber(b), tonumber(n) }
end
end
return ports
end
function usbport.validate(self, value)
return type(value) == "string" and { value } or value
end
for p in nixio.fs.glob("/sys/bus/usb/devices/[0-9]*/manufacturer") do
local id = p:match("%d+-%d+")
local mf = nixio.fs.readfile("/sys/bus/usb/devices/" .. id .. "/manufacturer") or "?"
local pr = nixio.fs.readfile("/sys/bus/usb/devices/" .. id .. "/product") or "?"
usbdev:value(id, "%s (%s - %s)" %{ id, mf, pr })
end
for p in nixio.fs.glob("/sys/bus/usb/devices/*/usb[0-9]*-port[0-9]*") do
local bus, port = p:match("usb(%d+)-port(%d+)")
if bus and port then
usbport:value("usb%u-port%u" %{ tonumber(bus), tonumber(port) },
"Hub %u, Port %u" %{ tonumber(bus), tonumber(port) })
end
end
port_mask = s:option(Value, "port_mask", translate ("Switch Port Mask"))
port_mask:depends("trigger", "switch0")
return m

View file

@ -1,97 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2010-2012 Jo-Philipp Wich <jow@openwrt.org>
-- Copyright 2010 Manuel Munz <freifunk at somakoma dot de>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local sys = require "luci.sys"
local inits = { }
for _, name in ipairs(sys.init.names()) do
local index = sys.init.index(name)
local enabled = sys.init.enabled(name)
if index < 255 then
inits["%02i.%s" % { index, name }] = {
name = name,
index = tostring(index),
enabled = enabled
}
end
end
m = SimpleForm("initmgr", translate("Initscripts"), translate("You can enable or disable installed init scripts here. Changes will applied after a device reboot.<br /><strong>Warning: If you disable essential init scripts like \"network\", your device might become inaccessible!</strong>"))
m.reset = false
m.submit = false
s = m:section(Table, inits)
i = s:option(DummyValue, "index", translate("Start priority"))
n = s:option(DummyValue, "name", translate("Initscript"))
e = s:option(Button, "endisable", translate("Enable/Disable"))
e.render = function(self, section, scope)
if inits[section].enabled then
self.title = translate("Enabled")
self.inputstyle = "save"
else
self.title = translate("Disabled")
self.inputstyle = "reset"
end
Button.render(self, section, scope)
end
e.write = function(self, section)
if inits[section].enabled then
inits[section].enabled = false
return sys.init.disable(inits[section].name)
else
inits[section].enabled = true
return sys.init.enable(inits[section].name)
end
end
start = s:option(Button, "start", translate("Start"))
start.inputstyle = "apply"
start.write = function(self, section)
sys.call("/etc/init.d/%s %s >/dev/null" %{ inits[section].name, self.option })
end
restart = s:option(Button, "restart", translate("Restart"))
restart.inputstyle = "reload"
restart.write = start.write
stop = s:option(Button, "stop", translate("Stop"))
stop.inputstyle = "remove"
stop.write = start.write
f = SimpleForm("rc", translate("Local Startup"),
translate("This is the content of /etc/rc.local. Insert your own commands here (in front of 'exit 0') to execute them at the end of the boot process."))
t = f:field(TextValue, "rcs")
t.rmempty = true
t.rows = 20
function t.cfgvalue()
return fs.readfile("/etc/rc.local") or ""
end
function f.handle(self, state, data)
if state == FORM_VALID then
if data.rcs then
fs.writefile("/etc/rc.local", data.rcs:gsub("\r\n", "\n"))
end
end
return true
end
return m, f

View file

@ -1,224 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local sys = require "luci.sys"
local zones = require "luci.sys.zoneinfo"
local fs = require "nixio.fs"
local conf = require "luci.config"
local m, s, o
local has_ntpd = fs.access("/usr/sbin/ntpd")
m = Map("system", translate("System"), translate("Here you can configure the basic aspects of your device like its hostname or the timezone."))
m:chain("luci")
s = m:section(TypedSection, "system", translate("System Properties"))
s.anonymous = true
s.addremove = false
s:tab("general", translate("General Settings"))
s:tab("logging", translate("Logging"))
s:tab("language", translate("Language and Style"))
--
-- System Properties
--
o = s:taboption("general", DummyValue, "_systime", translate("Local Time"))
o.template = "admin_system/clock_status"
o = s:taboption("general", Value, "hostname", translate("Hostname"))
o.datatype = "hostname"
function o.write(self, section, value)
Value.write(self, section, value)
sys.hostname(value)
end
o = s:taboption("general", ListValue, "zonename", translate("Timezone"))
o:value("UTC")
for i, zone in ipairs(zones.TZ) do
o:value(zone[1])
end
function o.write(self, section, value)
local function lookup_zone(title)
for _, zone in ipairs(zones.TZ) do
if zone[1] == title then return zone[2] end
end
end
AbstractValue.write(self, section, value)
local timezone = lookup_zone(value) or "GMT0"
self.map.uci:set("system", section, "timezone", timezone)
fs.writefile("/etc/TZ", timezone .. "\n")
end
--
-- Logging
--
o = s:taboption("logging", Value, "log_size", translate("System log buffer size"), "kiB")
o.optional = true
o.placeholder = 16
o.datatype = "uinteger"
o = s:taboption("logging", Value, "log_ip", translate("External system log server"))
o.optional = true
o.placeholder = "0.0.0.0"
o.datatype = "ip4addr"
o = s:taboption("logging", Value, "log_port", translate("External system log server port"))
o.optional = true
o.placeholder = 514
o.datatype = "port"
o = s:taboption("logging", ListValue, "log_proto", translate("External system log server protocol"))
o:value("udp", "UDP")
o:value("tcp", "TCP")
o = s:taboption("logging", Value, "log_file", translate("Write system log to file"))
o.optional = true
o.placeholder = "/tmp/system.log"
o = s:taboption("logging", ListValue, "conloglevel", translate("Log output level"))
o:value(8, translate("Debug"))
o:value(7, translate("Info"))
o:value(6, translate("Notice"))
o:value(5, translate("Warning"))
o:value(4, translate("Error"))
o:value(3, translate("Critical"))
o:value(2, translate("Alert"))
o:value(1, translate("Emergency"))
o = s:taboption("logging", ListValue, "cronloglevel", translate("Cron Log Level"))
o.default = 8
o:value(5, translate("Debug"))
o:value(8, translate("Normal"))
o:value(9, translate("Warning"))
--
-- Langauge & Style
--
o = s:taboption("language", ListValue, "_lang", translate("Language"))
o:value("auto")
local i18ndir = luci.i18n.i18ndir .. "base."
for k, v in luci.util.kspairs(conf.languages) do
local file = i18ndir .. k:gsub("_", "-")
if k:sub(1, 1) ~= "." and fs.access(file .. ".lmo") then
o:value(k, v)
end
end
function o.cfgvalue(...)
return m.uci:get("luci", "main", "lang")
end
function o.write(self, section, value)
m.uci:set("luci", "main", "lang", value)
end
o = s:taboption("language", ListValue, "_mediaurlbase", translate("Design"))
for k, v in pairs(conf.themes) do
if k:sub(1, 1) ~= "." then
o:value(v, k)
end
end
function o.cfgvalue(...)
return m.uci:get("luci", "main", "mediaurlbase")
end
function o.write(self, section, value)
m.uci:set("luci", "main", "mediaurlbase", value)
end
--
-- NTP
--
if has_ntpd then
-- timeserver setup was requested, create section and reload page
if m:formvalue("cbid.system._timeserver._enable") then
m.uci:section("system", "timeserver", "ntp",
{
server = { "0.openwrt.pool.ntp.org", "1.openwrt.pool.ntp.org", "2.openwrt.pool.ntp.org", "3.openwrt.pool.ntp.org" }
}
)
m.uci:save("system")
luci.http.redirect(luci.dispatcher.build_url("admin/system", arg[1]))
return
end
local has_section = false
m.uci:foreach("system", "timeserver",
function(s)
has_section = true
return false
end)
if not has_section then
s = m:section(TypedSection, "timeserver", translate("Time Synchronization"))
s.anonymous = true
s.cfgsections = function() return { "_timeserver" } end
x = s:option(Button, "_enable")
x.title = translate("Time Synchronization is not configured yet.")
x.inputtitle = translate("Set up Time Synchronization")
x.inputstyle = "apply"
else
s = m:section(TypedSection, "timeserver", translate("Time Synchronization"))
s.anonymous = true
s.addremove = false
o = s:option(Flag, "enable", translate("Enable NTP client"))
o.rmempty = false
function o.cfgvalue(self)
return sys.init.enabled("sysntpd")
and self.enabled or self.disabled
end
function o.write(self, section, value)
if value == self.enabled then
sys.init.enable("sysntpd")
sys.call("env -i /etc/init.d/sysntpd start >/dev/null")
else
sys.call("env -i /etc/init.d/sysntpd stop >/dev/null")
sys.init.disable("sysntpd")
end
end
o = s:option(Flag, "enable_server", translate("Provide NTP server"))
o:depends("enable", "1")
o = s:option(DynamicList, "server", translate("NTP server candidates"))
o.datatype = "host(0)"
o:depends("enable", "1")
-- retain server list even if disabled
function o.remove() end
end
end
return m

View file

@ -1,137 +0,0 @@
<%#
Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<%
local fs = require "nixio.fs"
local has_ping6 = fs.access("/bin/ping6") or fs.access("/usr/bin/ping6")
local has_traceroute6 = fs.access("/bin/traceroute6") or fs.access("/usr/bin/traceroute6")
local has_speedtest = fs.access("/usr/sbin/speedtestc")
local has_curl = fs.access("/usr/bin/curl")
local has_netstat = fs.access("/bin/netstat")
local dns_host = luci.config.diag and luci.config.diag.dns or "dev.openwrt.org"
local ping_host = luci.config.diag and luci.config.diag.ping or "dev.openwrt.org"
local route_host = luci.config.diag and luci.config.diag.route or "dev.openwrt.org"
local getip_host = luci.config.diag and luci.config.diag.getip or "ifconfig.co"
%>
<script type="text/javascript">//<![CDATA[
var stxhr = new XHR();
function update_status(field, proto)
{
var tool = field.name;
var addr = field.value;
var protocol = proto ? "6" : "";
var legend = document.getElementById('diag-rc-legend');
var output = document.getElementById('diag-rc-output');
if (legend && output)
{
output.innerHTML =
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /> ' +
'<%:Waiting for command to complete...%>'
;
legend.parentNode.style.display = 'block';
legend.style.display = 'inline';
stxhr.post('<%=url('admin/network')%>/diag_' + tool + protocol + '/' + addr, { token: '<%=token%>' },
function(x)
{
if (x.responseText)
{
legend.style.display = 'none';
output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
}
else
{
legend.style.display = 'none';
output.innerHTML = '<span class="error"><%:Bad address specified!%></span>';
}
}
);
}
}
//]]></script>
<form method="post" action="<%=url('admin/network/diagnostics')%>">
<div class="cbi-map">
<h2 name="content"><%:Diagnostics%></h2>
<div class="cbi-section">
<legend><%:Network Utilities%></legend>
<div class="table">
<div class="tr">
<div class="td left">
<input style="margin: 5px 0" type="text" value="<%=ping_host%>" name="ping" /><br />
<% if has_ping6 then %>
<select name="ping_proto" style="width:auto">
<option value="" selected="selected"><%:IPv4%></option>
<option value="6"><%:IPv6%></option>
</select>
<input type="button" value="<%:Ping%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.ping, this.form.ping_proto.selectedIndex)" />
<% else %>
<input type="button" value="<%:Ping%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.ping)" />
<% end %>
</div>
<div class="td left">
<input style="margin: 5px 0" type="text" value="<%=route_host%>" name="traceroute" /><br />
<% if has_traceroute6 then %>
<select name="traceroute_proto" style="width:auto">
<option value="" selected="selected"><%:IPv4%></option>
<option value="6"><%:IPv6%></option>
</select>
<input type="button" value="<%:Traceroute%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.traceroute, this.form.traceroute_proto.selectedIndex)" />
<% else %>
<input type="button" value="<%:Traceroute%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.traceroute)" />
<% end %>
<% if not has_traceroute6 then %>
<p>&#160;</p>
<p><%:Install iputils-traceroute6 for IPv6 traceroute%></p>
<% end %>
</div>
<div class="td left">
<input style="margin: 5px 0" type="text" value="<%=dns_host%>" name="nslookup" /><br />
<input type="button" value="<%:Nslookup%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.nslookup)" />
</div>
<% if has_speedtest and false then %>
<div class="td left">
<input style="margin: 5px 0" type="text" value="" name="speedtest" placeholder="alternate server" /><br />
<input type="button" value="<%:Speedtest%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.speedtest)" />
</div>
<% end %>
<% if has_curl then %>
<div class="td left">
<input style="margin: 5px 0" type="hidden" value="<%=getip_host%>" name="getip" /><br />
<input type="button" value="<%:Get public IP%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.getip)" />
</div>
<% end %>
<% if has_netstat then %>
<div class="td left">
<input style="margin: 5px 0" type="hidden" value="" name="netstat" /><br />
<input type="button" value="<%:Netstat%>" class="cbi-button cbi-button-apply" onclick="update_status(this.form.netstat)" />
</div>
<% end %>
</div>
</div>
</div>
</div>
<div class="cbi-section" style="display:none">
<strong id="diag-rc-legend"></strong>
<span id="diag-rc-output"></span>
</div>
</form>
<%+footer%>

View file

@ -1,183 +0,0 @@
<%#
Copyright 2010-2018 Jo-Philipp Wich <jo@mein.io>
Licensed to the public under the Apache License 2.0.
-%>
<script type="text/javascript">//<![CDATA[
function iface_reconnect(id) {
XHR.halt();
var d = document.getElementById(id + '-ifc-description');
if (d) d.innerHTML = '<em><%:Interface is reconnecting...%></em>';
(new XHR()).post('<%=url('admin/network/iface_reconnect')%>/' + id,
{ token: '<%=token%>' }, XHR.run);
}
function iface_delete(ev) {
if (!confirm(<%=luci.http.write_json(translate('Really delete this interface? The deletion cannot be undone! You might lose access to this device if you are connected via this interface'))%>)) {
ev.preventDefault();
return false;
}
ev.target.previousElementSibling.value = '1';
return true;
}
var networks = [];
document.querySelectorAll('[data-network]').forEach(function(n) {
networks.push(n.getAttribute('data-network'));
});
function render_iface(ifc) {
return E('span', { class: 'cbi-tooltip-container' }, [
E('img', { 'class' : 'middle', 'src': '<%=resource%>/icons/%s%s.png'.format(
ifc.is_alias ? 'alias' : ifc.type,
ifc.is_up ? '' : '_disabled') }),
E('span', { 'class': 'cbi-tooltip ifacebadge large' }, [
E('img', { 'src': '<%=resource%>/icons/%s%s.png'.format(
ifc.type, ifc.is_up ? '' : '_disabled') }),
E('span', { 'class': 'left' }, [
E('strong', '<%:Type%>: '), ifc.typename, E('br'),
E('strong', '<%:Device%>: '), ifc.ifname, E('br'),
E('strong', '<%:Connected%>: '), ifc.is_up ? '<%:yes%>' : '<%:no%>', E('br'),
ifc.macaddr ? E('strong', '<%:MAC%>: ') : '',
ifc.macaddr ? ifc.macaddr : '',
ifc.macaddr ? E('br') : '',
E('strong', '<%:RX%>: '), '%.2mB (%d <%:Pkts.%>)'.format(ifc.rx_bytes, ifc.rx_packets), E('br'),
E('strong', '<%:TX%>: '), '%.2mB (%d <%:Pkts.%>)'.format(ifc.tx_bytes, ifc.tx_packets)
])
])
]);
}
XHR.poll(5, '<%=url('admin/network/iface_status')%>/' + networks.join(','), null,
function(x, ifcs)
{
if (ifcs)
{
for (var idx = 0; idx < ifcs.length; idx++)
{
var ifc = ifcs[idx];
var html = '';
var s = document.getElementById(ifc.id + '-ifc-devices');
if (s)
{
while (s.firstChild)
s.removeChild(s.firstChild);
s.appendChild(render_iface(ifc));
if (ifc.subdevices && ifc.subdevices.length)
{
var sifs = [ ' (' ];
for (var j = 0; j < ifc.subdevices.length; j++)
sifs.push(render_iface(ifc.subdevices[j]));
sifs.push(')');
s.appendChild(E('span', {}, sifs));
}
s.appendChild(E('br'));
s.appendChild(E('small', {}, ifc.is_alias ? '<%:Alias of "%s"%>'.format(ifc.is_alias) : ifc.name));
}
var d = document.getElementById(ifc.id + '-ifc-description');
if (d && ifc.proto && ifc.ifname)
{
var desc = null;
if (ifc.is_dynamic)
desc = '<%:Virtual dynamic interface%>';
else if (ifc.is_alias)
desc = '<%:Alias Interface%>';
if (ifc.desc)
desc = desc ? '%s (%s)'.format(desc, ifc.desc) : ifc.desc;
html += String.format('<strong><%:Protocol%>:</strong> %h<br />', desc || '?');
if (ifc.is_up)
{
html += String.format('<strong><%:Uptime%>:</strong> %t<br />', ifc.uptime);
}
if (!ifc.is_dynamic && !ifc.is_alias)
{
if (ifc.macaddr)
html += String.format('<strong><%:MAC%>:</strong> %s<br />', ifc.macaddr);
html += String.format(
'<strong><%:RX%>:</strong> %.2mB (%d <%:Pkts.%>)<br />' +
'<strong><%:TX%>:</strong> %.2mB (%d <%:Pkts.%>)<br />',
ifc.rx_bytes, ifc.rx_packets,
ifc.tx_bytes, ifc.tx_packets
);
}
if (ifc.ipaddrs && ifc.ipaddrs.length)
{
for (var i = 0; i < ifc.ipaddrs.length; i++)
html += String.format(
'<strong><%:IPv4%>:</strong> %s<br />',
ifc.ipaddrs[i]
);
}
if (ifc.ip6addrs && ifc.ip6addrs.length)
{
for (var i = 0; i < ifc.ip6addrs.length; i++)
html += String.format(
'<strong><%:IPv6%>:</strong> %s<br />',
ifc.ip6addrs[i]
);
}
if (ifc.ip6prefix)
html += String.format('<strong><%:IPv6-PD%>:</strong> %s<br />', ifc.ip6prefix);
if (ifc.errors)
{
for (var i = 0; i < ifc.errors.length; i++)
html += String.format(
'<em class="error"><strong><%:Error%>:</strong> %h</em><br />',
ifc.errors[i]
);
}
d.innerHTML = html;
}
else if (d && !ifc.proto)
{
var e = document.getElementById(ifc.id + '-ifc-edit');
if (e)
e.disabled = true;
d.innerHTML = String.format(
'<em><%:Unsupported protocol type.%></em><br />' +
'<a href="%h"><%:Install protocol extensions...%></a>',
'<%=url("admin/system/packages")%>?query=luci-proto&display=available'
);
}
else if (d && !ifc.ifname)
{
d.innerHTML = String.format(
'<em><%:Network without interfaces.%></em><br />' +
'<a href="<%=url("admin/network/network/%s")%>?tab.network.%s=physical"><%:Assign interfaces...%></a>',
ifc.name, ifc.name
);
}
else if (d)
{
d.innerHTML = '<em><%:Interface not present or not connected yet.%></em>';
}
}
}
}
);
//]]></script>

View file

@ -1,66 +0,0 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=url('admin/network/iface_status', self.network)%>', null,
function(x, ifc)
{
if (ifc && (ifc = ifc[0]))
{
var s = document.getElementById('<%=self.option%>-ifc-status'),
img = s.querySelector('img'),
info = s.querySelector('span'),
html = '<strong><%:Device%>:</strong> %h<br />'.format(ifc.ifname);
if (ifc.ifname)
{
if (ifc.is_up)
html += String.format('<strong><%:Uptime%>:</strong> %t<br />', ifc.uptime);
if (ifc.macaddr)
html += String.format('<strong><%:MAC%>:</strong> %s<br />', ifc.macaddr);
html += String.format(
'<strong><%:RX%></strong>: %.2mB (%d <%:Pkts.%>)<br />' +
'<strong><%:TX%></strong>: %.2mB (%d <%:Pkts.%>)<br />',
ifc.rx_bytes, ifc.rx_packets,
ifc.tx_bytes, ifc.tx_packets
);
if (ifc.ipaddrs && ifc.ipaddrs.length)
for (var i = 0; i < ifc.ipaddrs.length; i++)
html += String.format(
'<strong><%:IPv4%>:</strong> %s<br />',
ifc.ipaddrs[i]
);
if (ifc.ip6addrs && ifc.ip6addrs.length)
for (var i = 0; i < ifc.ip6addrs.length; i++)
html += String.format(
'<strong><%:IPv6%>:</strong> %s<br />',
ifc.ip6addrs[i]
);
if (ifc.ip6prefix)
html += String.format('<strong><%:IPv6-PD%>:</strong> %s<br />', ifc.ip6prefix);
info.innerHTML = html;
}
else
{
info.innerHTML = '<em><%:Interface not present or not connected yet.%></em>';
}
img.src = '<%=resource%>/icons/%s%s.png'.format(ifc.type, ifc.is_up ? '' : '_disabled');
}
}
);
//]]></script>
<span class="ifacebadge large" id="<%=self.option%>-ifc-status">
<img src="<%=resource%>/icons/ethernet_disabled.png" />
<span>
<em><%:Collecting data...%></em>
</span>
</span>
<%+cbi/valuefooter%>

View file

@ -1,95 +0,0 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=url('admin/network/dhcplease_status')%>', null,
function(x, st)
{
var tb = document.getElementById('lease_status_table');
if (st && st[0] && tb)
{
var rows = [];
for (var i = 0; i < st[0].length; i++)
{
var timestr;
if (st[0][i].expires === false)
timestr = '<em><%:unlimited%></em>';
else if (st[0][i].expires <= 0)
timestr = '<em><%:expired%></em>';
else
timestr = String.format('%t', st[0][i].expires);
rows.push([
st[0][i].hostname || '?',
st[0][i].ipaddr,
st[0][i].macaddr,
timestr
]);
}
cbi_update_table(tb, rows, '<em><%:There are no active leases.%></em>');
}
var tb6 = document.getElementById('lease6_status_table');
if (st && st[1] && tb6)
{
tb6.parentNode.style.display = 'block';
var rows = [];
for (var i = 0; i < st[1].length; i++)
{
var timestr;
if (st[1][i].expires === false)
timestr = '<em><%:unlimited%></em>';
else if (st[1][i].expires <= 0)
timestr = '<em><%:expired%></em>';
else
timestr = String.format('%t', st[1][i].expires);
var name = st[1][i].hostname,
hint = st[1][i].host_hint;
rows.push([
hint ? '%h (%h)'.format(name || '?', hint) : (name || '?'),
st[1][i].ip6addr,
st[1][i].duid,
timestr
]);
}
cbi_update_table(tb6, rows, '<em><%:There are no active leases.%></em>');
}
}
);
//]]></script>
<div class="cbi-section">
<h3><%:Active DHCP Leases%></h3>
<div class="table" id="lease_status_table">
<div class="tr table-titles">
<div class="th"><%:Hostname%></div>
<div class="th"><%:IPv4-Address%></div>
<div class="th"><%:MAC-Address%></div>
<div class="th"><%:Leasetime remaining%></div>
</div>
<div class="tr placeholder">
<div class="td"><em><%:Collecting data...%></em></div>
</div>
</div>
</div>
<div class="cbi-section" style="display:none">
<h3><%:Active DHCPv6 Leases%></h3>
<div class="table" id="lease6_status_table">
<div class="tr table-titles">
<div class="th"><%:Host%></div>
<div class="th"><%:IPv6-Address%></div>
<div class="th"><%:DUID%></div>
<div class="th"><%:Leasetime remaining%></div>
</div>
<div class="tr placeholder">
<div class="td"><em><%:Collecting data...%></em></div>
</div>
</div>
</div>

View file

@ -1,62 +0,0 @@
<script type="text/javascript">//<![CDATA[
var switches = [ '<%=table.concat(self.switches, "', '")%>' ],
tables = document.querySelectorAll('.cbi-section-table');
function add_status_row(table) {
var first_row = table.querySelector('.cbi-section-table-row');
if (first_row.classList.contains('port-status'))
return first_row;
var status_row = first_row.parentNode.insertBefore(
E('div', { 'class': first_row.className }), first_row);
first_row.querySelectorAll('.td').forEach(function(td) {
status_row.appendChild(td.cloneNode(false));
status_row.lastElementChild.removeAttribute('data-title');
});
status_row.firstElementChild.innerHTML = '<%:Port status:%>';
status_row.classList.add('port-status') ;
return status_row;
}
XHR.poll(5, '<%=url('admin/network/switch_status')%>/' + switches.join(','), null,
function(x, st)
{
for (var i = 0; i < switches.length; i++)
{
var ports = st[switches[i]];
var tr = add_status_row(tables[i]);
if (tr && ports && ports.length)
{
for (var j = 0; j < ports.length; j++)
{
var th = tr.querySelector('[data-name="%d"]'.format(j));
if (!th)
continue;
if (ports[j].link)
{
th.innerHTML = String.format(
'<small><img src="<%=resource%>/icons/port_up.png" />' +
'<br />%d<%:baseT%><br />%s</small>',
ports[j].speed, ports[j].duplex
? '<%:full-duplex%>' : '<%:half-duplex%>'
);
}
else
{
th.innerHTML = String.format(
'<small><img src="<%=resource%>/icons/port_down.png" />' +
'<br /><%:no link%></small>'
);
}
}
}
}
}
);
//]]></script>

View file

@ -1,82 +0,0 @@
<script type="text/javascript">//<![CDATA[
function wifirate(bss, rx) {
var p = rx ? 'rx_' : 'tx_',
s = '%.1f <%:Mbit/s%>, %d<%:MHz%>'
.format(bss[p+'rate'] / 1000, bss[p+'mhz']),
ht = bss[p+'ht'], vht = bss[p+'vht'],
mhz = bss[p+'mhz'], nss = bss[p+'nss'],
mcs = bss[p+'mcs'], sgi = bss[p+'short_gi'];
if (ht || vht) {
if (vht) s += ', VHT-MCS %d'.format(mcs);
if (nss) s += ', VHT-NSS %d'.format(nss);
if (ht) s += ', MCS %s'.format(mcs);
if (sgi) s += ', <%:Short GI%>';
}
return s;
}
XHR.poll(5, '<%=url('admin/network/wireless_assoclist')%>', null,
function(x, st)
{
var tb = document.getElementById('wifi_assoclist_table');
if (st && tb)
{
var rows = [];
st.forEach(function(bss) {
var icon;
var q = (-1 * (bss.noise - bss.signal)) / 5;
if (q < 1)
icon = "<%=resource%>/icons/signal-0.png";
else if (q < 2)
icon = "<%=resource%>/icons/signal-0-25.png";
else if (q < 3)
icon = "<%=resource%>/icons/signal-25-50.png";
else if (q < 4)
icon = "<%=resource%>/icons/signal-50-75.png";
else
icon = "<%=resource%>/icons/signal-75-100.png";
rows.push([
'<span class="ifacebadge" title="%q"><img src="<%=resource%>/icons/wifi.png" /> <a href="%s">%h</a><small>&#160;(%h)</small></span>'.format(
bss.radio,
bss.link,
bss.name,
bss.ifname),
bss.bssid,
bss.host_hint ? '%h (%h)'.format(bss.host_name || '?', bss.host_hint) : (bss.host_name || '?'),
'<span class="ifacebadge" title="<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%> / <%:SNR%>: %d"><img src="%s" /> %d / %d <%:dBm%></span>'.format(
bss.signal,
bss.noise,
bss.signal - bss.noise,
icon,
bss.signal,
bss.noise),
E('span', {}, [
E('span', wifirate(bss, true)),
E('br'),
E('span', wifirate(bss, false))
])
]);
});
cbi_update_table(tb, rows, '<em><%:No information available%></em>');
}
}
);
//]]></script>
<div class="table" id="wifi_assoclist_table">
<div class="tr table-titles">
<div class="th nowrap"><%:Network%></div>
<div class="th hide-xs"><%:MAC-Address%></div>
<div class="th nowrap"><%:Host%></div>
<div class="th nowrap"><%:Signal%> / <%:Noise%></div>
<div class="th nowrap"><%:RX Rate%> / <%:TX Rate%></div>
</div>
<div class="tr placeholder">
<div class="td"><em><%:Collecting data...%></em></div>
</div>
</div>

View file

@ -1,224 +0,0 @@
<%#
Copyright 2009-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
local sys = require "luci.sys"
local utl = require "luci.util"
local dev = luci.http.formvalue("device")
local iw = luci.sys.wifi.getiwinfo(dev)
if not iw then
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
return
end
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
var xhr = new XHR(),
poll = null;
function format_signal(bss) {
var qval = bss.quality || 0,
qmax = bss.quality_max || 100,
scale = 100 / qmax * qval,
range = 'none';
if (!bss.bssid || bss.bssid == '00:00:00:00:00:00')
range = 'none';
else if (scale < 15)
range = '0';
else if (scale < 35)
range = '0-25';
else if (scale < 55)
range = '25-50';
else if (scale < 75)
range = '50-75';
else
range = '75-100';
return E('span', {
class: 'ifacebadge',
title: '<%:Signal%>: %d<%:dB%> / <%:Quality%>: %d/%d'.format(bss.signal, qval, qmax)
}, [
E('img', { src: '<%=resource%>/icons/signal-%s.png'.format(range) }),
' %d%%'.format(scale)
]);
}
function format_encryption(bss) {
var enc = bss.encryption || { }
if (enc.wep === true)
return 'WEP';
else if (enc.wpa > 0)
return E('abbr', {
title: 'Pairwise: %h / Group: %h'.format(
enc.pair_ciphers.join(', '),
enc.group_ciphers.join(', '))
},
'%h - %h'.format(
(enc.wpa === 3) ? '<%:mixed WPA/WPA2%>' : (enc.wpa === 2 ? 'WPA2' : 'WPA'),
enc.auth_suites.join(', ')));
else if (enc.enabled)
return '<em><%:unknown%></em>';
else
return '<em><%:open%></em>';
}
function format_actions(bss) {
var enc = bss.encryption || { },
input = [
E('input', { type: 'submit', class: 'cbi-button cbi-button-action important', value: '<%:Join Network%>' }),
E('input', { type: 'hidden', name: 'token', value: '<%=token%>' }),
E('input', { type: 'hidden', name: 'device', value: '<%=dev%>' }),
E('input', { type: 'hidden', name: 'join', value: bss.ssid }),
E('input', { type: 'hidden', name: 'mode', value: bss.mode }),
E('input', { type: 'hidden', name: 'bssid', value: bss.bssid }),
E('input', { type: 'hidden', name: 'channel', value: bss.channel }),
E('input', { type: 'hidden', name: 'clbridge', value: <%=iw.type == "wl" and 1 or 0%> }),
E('input', { type: 'hidden', name: 'wep', value: enc.wep ? 1 : 0 })
];
if (enc.wpa) {
input.push(E('input', { type: 'hidden', name: 'wpa_version', value: enc.wpa }));
enc.auth_suites.forEach(function(s) {
input.push(E('input', { type: 'hidden', name: 'wpa_suites', value: s }));
});
enc.group_ciphers.forEach(function(s) {
input.push(E('input', { type: 'hidden', name: 'wpa_group', value: s }));
});
enc.pair_ciphers.forEach(function(s) {
input.push(E('input', { type: 'hidden', name: 'wpa_pairwise', value: s }));
});
}
return E('form', {
class: 'inline',
method: 'post',
action: '<%=url("admin/network/wireless_join")%>'
}, input);
}
function fade(bss, content) {
if (bss.stale)
return E('span', { style: 'opacity:0.5' }, content);
else
return content;
}
function flush() {
XHR.stop(poll);
XHR.halt();
scan();
}
function scan() {
var tbl = document.getElementById('scan_results');
cbi_update_table(tbl, [], '<em><img src="<%=resource%>/icons/loading.gif" class="middle" /> <%:Starting wireless scan...%></em>');
xhr.post('<%=url("admin/network/wireless_scan_trigger", dev)%>', { token: '<%=token%>' },
function(s) {
if (s.status !== 200) {
cbi_update_table(tbl, [], '<em><%:Scan request failed%></em>');
return;
}
var count = 0;
poll = XHR.poll(3, '<%=url("admin/network/wireless_scan_results", dev)%>', null,
function(s, results) {
if (Array.isArray(results)) {
var bss = [];
results.sort(function(a, b) {
var diff = (b.quality - a.quality) || (a.channel - b.channel);
if (diff)
return diff;
if (a.ssid < b.ssid)
return -1;
else if (a.ssid > b.ssid)
return 1;
if (a.bssid < b.bssid)
return -1;
else if (a.bssid > b.bssid)
return 1;
}).forEach(function(res) {
bss.push([
fade(res, format_signal(res)),
fade(res, res.ssid ? '%h'.format(res.ssid) : E('em', {}, '<%:hidden%>')),
fade(res, res.channel),
fade(res, res.mode),
fade(res, res.bssid),
fade(res, format_encryption(res)),
format_actions(res)
]);
});
cbi_update_table(tbl, bss, '<em><img src="<%=resource%>/icons/loading.gif" class="middle" /> <%:No scan results available yet...%>');
}
if (count++ >= 3) {
count = 0;
xhr.post('<%=url("admin/network/wireless_scan_trigger", dev, "1")%>',
{ token: '<%=token%>' }, function() { });
}
});
XHR.run();
});
}
document.addEventListener('DOMContentLoaded', scan);
//]]></script>
<h2 name="content"><%:Join Network: Wireless Scan%></h2>
<div class="cbi-map">
<div class="cbi-section">
<div class="table" id="scan_results">
<div class="tr table-titles">
<div class="th col-1 middle center"><%:Signal%></div>
<div class="th col-5 middle left"><%:SSID%></div>
<div class="th col-2 middle center"><%:Channel%></div>
<div class="th col-2 middle left"><%:Mode%></div>
<div class="th col-3 middle left"><%:BSSID%></div>
<div class="th col-2 middle left"><%:Encryption%></div>
<div class="th cbi-section-actions">&#160;</div>
</div>
<div class="tr placeholder">
<div class="td">
<img src="<%=resource%>/icons/loading.gif" class="middle" />
<em><%:Collecting data...%></em>
</div>
</div>
</div>
</div>
</div>
<div class="cbi-page-actions right">
<form class="inline" action="<%=url("admin/network/wireless")%>" method="get">
<input class="cbi-button cbi-button-neutral" type="submit" value="<%:Back to overview%>" />
</form>
<form class="inline" action="<%=url('admin/network/wireless_join')%>" method="post">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" />
<input type="button" class="cbi-button cbi-button-action" value="<%:Repeat scan%>" onclick="flush()" />
</form>
</div>
<%+footer%>

View file

@ -1,127 +0,0 @@
<%#
Copyright 2008-2009 Steven Barth <steven@midlink.org>
Copyright 2008-2018 Jo-Philipp Wich <jo@mein.io>
Licensed to the public under the Apache License 2.0.
-%>
<script type="text/javascript">//<![CDATA[
function wifi_delete(ev) {
if (!confirm(<%=luci.http.write_json(translate('Really delete this wireless network? The deletion cannot be undone! You might lose access to this device if you are connected via this network.'))%>)) {
ev.preventDefault();
return false;
}
ev.target.previousElementSibling.value = '1';
return true;
}
function wifi_restart(ev) {
XHR.halt();
findParent(ev.target, '.table').querySelectorAll('[data-disabled="false"]').forEach(function(s) {
s.innerHTML = '<em><%:Wireless is restarting...%></em>';
});
(new XHR()).post('<%=url('admin/network/wireless_reconnect')%>/' + ev.target.getAttribute('data-radio'),
{ token: '<%=token%>' }, XHR.run);
}
var networks = [ ];
document.querySelectorAll('[data-network]').forEach(function(n) {
networks.push(n.getAttribute('data-network'));
});
XHR.poll(5, '<%=url('admin/network/wireless_status')%>/' + networks.join(','), null,
function(x, st)
{
if (st)
{
var rowstyle = 1;
var radiostate = { };
st.forEach(function(s) {
var r = radiostate[s.device.device] || (radiostate[s.device.device] = {});
s.is_assoc = (s.bssid && s.bssid != '00:00:00:00:00:00' && s.channel && s.mode != 'Unknown' && !s.disabled);
r.up = r.up || s.is_assoc;
r.channel = r.channel || s.channel;
r.bitrate = r.bitrate || s.bitrate;
r.frequency = r.frequency || s.frequency;
});
for( var i = 0; i < st.length; i++ )
{
var iw = st[i],
sig = document.getElementById(iw.id + '-iw-signal'),
info = document.getElementById(iw.id + '-iw-status'),
disabled = (info && info.getAttribute('data-disabled') === 'true');
var p = iw.quality;
var q = disabled ? -1 : p;
var icon;
if (q < 0)
icon = "<%=resource%>/icons/signal-none.png";
else if (q == 0)
icon = "<%=resource%>/icons/signal-0.png";
else if (q < 25)
icon = "<%=resource%>/icons/signal-0-25.png";
else if (q < 50)
icon = "<%=resource%>/icons/signal-25-50.png";
else if (q < 75)
icon = "<%=resource%>/icons/signal-50-75.png";
else
icon = "<%=resource%>/icons/signal-75-100.png";
if (sig)
sig.innerHTML = String.format(
'<span class="ifacebadge" title="<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%>"><img src="%s" /> %d%%</span>',
iw.signal, iw.noise, icon, p
);
if (info)
{
if (iw.is_assoc)
info.innerHTML = String.format(
'<strong><%:SSID%>:</strong> %h | ' +
'<strong><%:Mode%>:</strong> %s<br />' +
'<strong><%:BSSID%>:</strong> %s | ' +
'<strong><%:Encryption%>:</strong> %s',
iw.ssid, iw.mode, iw.bssid,
iw.encryption ? iw.encryption : '<%:None%>'
);
else
info.innerHTML = String.format(
'<strong><%:SSID%>:</strong> %h | ' +
'<strong><%:Mode%>:</strong> %s<br />' +
'<em>%s</em>',
iw.ssid || '?', iw.mode,
disabled ? '<em><%:Wireless is disabled%></em>'
: '<em><%:Wireless is not associated%></em>'
);
}
}
for (var dev in radiostate)
{
var img = document.getElementById(dev + '-iw-upstate');
if (img)
img.src = '<%=resource%>/icons/wifi' + (radiostate[dev].up ? '' : '_disabled') + '.png';
var stat = document.getElementById(dev + '-iw-devinfo');
if (stat)
stat.innerHTML = String.format(
'<strong><%:Channel%>:</strong> %s (%s <%:GHz%>) | ' +
'<strong><%:Bitrate%>:</strong> %s <%:Mbit/s%>',
radiostate[dev].channel ? radiostate[dev].channel : '?',
radiostate[dev].frequency ? radiostate[dev].frequency : '?',
radiostate[dev].bitrate ? radiostate[dev].bitrate : '?'
);
}
}
}
);
//]]></script>

View file

@ -1,77 +0,0 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=url('admin/network/wireless_status', self.ifname)%>', null,
function(x, iw)
{
if (iw && (iw = iw[0]))
{
var is_assoc = (iw.bssid && iw.bssid != '00:00:00:00:00:00' && iw.channel && !iw.disabled);
var p = iw.quality;
var q = iw.disabled ? -1 : p;
var icon;
if (q < 0)
icon = "<%=resource%>/icons/signal-none.png";
else if (q == 0)
icon = "<%=resource%>/icons/signal-0.png";
else if (q < 25)
icon = "<%=resource%>/icons/signal-0-25.png";
else if (q < 50)
icon = "<%=resource%>/icons/signal-25-50.png";
else if (q < 75)
icon = "<%=resource%>/icons/signal-50-75.png";
else
icon = "<%=resource%>/icons/signal-75-100.png";
var s = document.getElementById('<%=self.option%>-iw-status'),
small = s.querySelector('small'),
info = s.querySelector('span');
small.innerHTML = info.innerHTML = String.format(
'<img src="%s" title="<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%>" />&#160;<br />%d%%&#160;',
icon, iw.signal, iw.noise, p
);
if (is_assoc)
info.innerHTML = String.format(
'<strong><%:Mode%>:</strong> %s | ' +
'<strong><%:SSID%>:</strong> %h<br />' +
'<strong><%:BSSID%>:</strong> %s<br />' +
'<strong><%:Encryption%>:</strong> %s<br />' +
'<strong><%:Channel%>:</strong> %d (%.3f <%:GHz%>)<br />' +
'<strong><%:Tx-Power%>:</strong> %d <%:dBm%><br />' +
'<strong><%:Signal%>:</strong> %d <%:dBm%> | ' +
'<strong><%:Noise%>:</strong> %d <%:dBm%><br />' +
'<strong><%:Bitrate%>:</strong> %.1f <%:Mbit/s%> | ' +
'<strong><%:Country%>:</strong> %s',
iw.mode, iw.ssid, iw.bssid,
iw.encryption ? iw.encryption : '<%:None%>',
iw.channel, iw.frequency ? iw.frequency : 0,
iw.txpower, iw.signal, iw.noise,
iw.bitrate ? iw.bitrate : 0, iw.country
);
else
info.innerHTML = String.format(
'<strong><%:SSID%>:</strong> %h | ' +
'<strong><%:Mode%>:</strong> %s<br />' +
'<em>%s</em>',
iw.ssid || '?', iw.mode,
iw.disabled ? '<em><%:Wireless is disabled%></em>'
: '<em><%:Wireless is not associated%></em>'
);
}
}
);
//]]></script>
<span class="ifacebadge large" id="<%=self.option%>-iw-status">
<small>
<img src="<%=resource%>/icons/signal-none.png" title="<%:Not associated%>" />&#160;
</small>
<span>
<em><%:Collecting data...%></em>
</span>
</span>
<%+cbi/valuefooter%>

View file

@ -1,305 +0,0 @@
<%#
Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
local ntm = require "luci.model.network".init()
local dev
local devices = { }
for _, dev in luci.util.vspairs(luci.sys.net.devices()) do
if dev ~= "lo" and not ntm:ignore_interface(dev) then
devices[#devices+1] = dev
end
end
local curdev = luci.http.formvalue("dev") or devices[1]
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
var bwxhr = new XHR();
var G;
var TIME = 0;
var RXB = 1;
var RXP = 2;
var TXB = 3;
var TXP = 4;
var width = 760;
var height = 300;
var step = 5;
var data_wanted = Math.floor(width / step);
var data_fill = 0;
var data_stamp = 0;
var data_rx = [ ];
var data_tx = [ ];
var line_rx;
var line_tx;
var label_25;
var label_50;
var label_75;
var label_rx_cur;
var label_rx_avg;
var label_rx_peak;
var label_tx_cur;
var label_tx_avg;
var label_tx_peak;
var label_scale;
Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; };
function bandwidth_label(bytes, br)
{
var uby = '<%:kB/s%>';
var kby = (bytes / 1024);
if (kby >= 1024)
{
uby = '<%:MB/s%>';
kby = kby / 1024;
}
var ubi = '<%:kbit/s%>';
var kbi = (bytes * 8 / 1024);
if (kbi >= 1024)
{
ubi = '<%:Mbit/s%>';
kbi = kbi / 1024;
}
return String.format("%f %s%s(%f %s)",
kbi.toFixed(2), ubi,
br ? '<br />' : ' ',
kby.toFixed(2), uby
);
}
/* wait for SVG */
window.setTimeout(
function() {
var svg = document.getElementById('bwsvg');
try {
G = svg.getSVGDocument
? svg.getSVGDocument() : svg.contentDocument;
}
catch(e) {
G = document.embeds['bwsvg'].getSVGDocument();
}
if (!G)
{
window.setTimeout(arguments.callee, 1000);
}
else
{
/* find sizes */
width = svg.offsetWidth - 2;
height = svg.offsetHeight - 2;
data_wanted = Math.ceil(width / step);
/* prefill datasets */
for (var i = 0; i < data_wanted; i++)
{
data_rx[i] = 0;
data_tx[i] = 0;
}
/* find svg elements */
line_rx = G.getElementById('rx');
line_tx = G.getElementById('tx');
label_25 = G.getElementById('label_25');
label_50 = G.getElementById('label_50');
label_75 = G.getElementById('label_75');
label_rx_cur = document.getElementById('rx_bw_cur');
label_rx_avg = document.getElementById('rx_bw_avg');
label_rx_peak = document.getElementById('rx_bw_peak');
label_tx_cur = document.getElementById('tx_bw_cur');
label_tx_avg = document.getElementById('tx_bw_avg');
label_tx_peak = document.getElementById('tx_bw_peak');
label_scale = document.getElementById('scale');
/* plot horizontal time interval lines */
for (var i = width % (step * 60); i < width; i += step * 60)
{
var line = G.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text = G.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(G.createTextNode(Math.round((width - i) / step / 60) + 'm'));
label_25.parentNode.appendChild(line);
label_25.parentNode.appendChild(text);
}
label_scale.innerHTML = String.format('<%:(%d minute window, %d second interval)%>', data_wanted / 60, 3);
/* render datasets, start update interval */
XHR.poll(3, '<%=build_url("admin/status/realtime/bandwidth_status", curdev)%>', null,
function(x, data)
{
var data_max = 0;
var data_scale = 0;
var data_rx_avg = 0;
var data_tx_avg = 0;
var data_rx_peak = 0;
var data_tx_peak = 0;
for (var i = data_stamp ? 0 : 1; i < data.length; i++)
{
/* skip overlapping entries */
if (data[i][TIME] <= data_stamp)
continue;
/* normalize difference against time interval */
if (i > 0)
{
var time_delta = data[i][TIME] - data[i-1][TIME];
if (time_delta)
{
data_rx.push((data[i][RXB] - data[i-1][RXB]) / time_delta);
data_tx.push((data[i][TXB] - data[i-1][TXB]) / time_delta);
}
}
}
/* cut off outdated entries */
data_rx = data_rx.slice(data_rx.length - data_wanted, data_rx.length);
data_tx = data_tx.slice(data_tx.length - data_wanted, data_tx.length);
/* find peak */
for (var i = 0; i < data_rx.length; i++)
{
data_max = Math.max(data_max, data_rx[i]);
data_max = Math.max(data_max, data_tx[i]);
data_rx_peak = Math.max(data_rx_peak, data_rx[i]);
data_tx_peak = Math.max(data_tx_peak, data_tx[i]);
data_rx_avg += data_rx[i];
data_tx_avg += data_tx[i];
}
data_rx_avg = (data_rx_avg / Math.max(data_rx.length, 1));
data_tx_avg = (data_tx_avg / Math.max(data_tx.length, 1));
var size = Math.floor(Math.log2(data_max)),
div = Math.pow(2, size - (size % 10)),
mult = data_max / div,
mult = (mult < 5) ? 2 : ((mult < 50) ? 10 : ((mult < 500) ? 100 : 1000));
data_max = data_max + (mult * div) - (data_max % (mult * div));
/* remember current timestamp, calculate horizontal scale */
data_stamp = data[data.length-1][TIME];
data_scale = height / data_max;
/* plot data */
var pt_rx = '0,' + height;
var pt_tx = '0,' + height;
var y_rx = 0;
var y_tx = 0;
for (var i = 0; i < data_rx.length; i++)
{
var x = i * step;
y_rx = height - Math.floor(data_rx[i] * data_scale);
y_tx = height - Math.floor(data_tx[i] * data_scale);
pt_rx += ' ' + x + ',' + y_rx;
pt_tx += ' ' + x + ',' + y_tx;
}
pt_rx += ' ' + width + ',' + y_rx + ' ' + width + ',' + height;
pt_tx += ' ' + width + ',' + y_tx + ' ' + width + ',' + height;
line_rx.setAttribute('points', pt_rx);
line_tx.setAttribute('points', pt_tx);
label_25.firstChild.data = bandwidth_label(0.25 * data_max);
label_50.firstChild.data = bandwidth_label(0.50 * data_max);
label_75.firstChild.data = bandwidth_label(0.75 * data_max);
label_rx_cur.innerHTML = bandwidth_label(data_rx[data_rx.length-1], true);
label_tx_cur.innerHTML = bandwidth_label(data_tx[data_tx.length-1], true);
label_rx_avg.innerHTML = bandwidth_label(data_rx_avg, true);
label_tx_avg.innerHTML = bandwidth_label(data_tx_avg, true);
label_rx_peak.innerHTML = bandwidth_label(data_rx_peak, true);
label_tx_peak.innerHTML = bandwidth_label(data_tx_peak, true);
}
);
XHR.run();
}
}, 1000
);
//]]></script>
<h2 name="content"><%:Realtime Traffic%></h2>
<ul class="cbi-tabmenu">
<% for _, dev in ipairs(devices) do %>
<li class="cbi-tab<%= dev == curdev and "" or "-disabled" %>"><a href="?dev=<%=pcdata(dev)%>"><%=pcdata(dev)%></a></li>
<% end %>
</ul>
<embed id="bwsvg" style="width:100%; height:300px; border:1px solid #000000; background-color:#FFFFFF" src="<%=resource%>/bandwidth.svg" />
<div style="text-align:right"><small id="scale">-</small></div>
<br />
<div class="table" style="width:100%; table-layout:fixed" cellspacing="5">
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid blue"><%:Inbound:%></strong></div>
<div class="td" id="rx_bw_cur">0 <%:kbit/s%><br />(0 <%:kB/s%>)</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="rx_bw_avg">0 <%:kbit/s%><br />(0 <%:kB/s%>)</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="rx_bw_peak">0 <%:kbit/s%><br />(0 <%:kB/s%>)</div>
</div>
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid green"><%:Outbound:%></strong></div>
<div class="td" id="tx_bw_cur">0 <%:kbit/s%><br />(0 <%:kB/s%>)</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="tx_bw_avg">0 <%:kbit/s%><br />(0 <%:kB/s%>)</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="tx_bw_peak">0 <%:kbit/s%><br />(0 <%:kB/s%>)</div>
</div>
</div>
<%+footer%>

View file

@ -1,376 +0,0 @@
<%#
Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
var bwxhr = new XHR();
var G;
var TIME = 0;
var UDP = 1;
var TCP = 2;
var OTHER = 3;
var width = 760;
var height = 300;
var step = 5;
var data_wanted = Math.floor(width / step);
var data_fill = 0;
var data_stamp = 0;
var data_udp = [ ];
var data_tcp = [ ];
var data_otr = [ ];
var line_udp;
var line_tcp;
var label_25;
var label_50;
var label_75;
var label_udp_cur;
var label_udp_avg;
var label_udp_peak;
var label_tcp_cur;
var label_tcp_avg;
var label_tcp_peak;
var label_otr_cur;
var label_otr_avg;
var label_otr_peak;
var label_scale;
var conn_table;
var dns_cache = { };
/* wait for SVG */
window.setTimeout(
function() {
var svg = document.getElementById('bwsvg');
try {
G = svg.getSVGDocument
? svg.getSVGDocument() : svg.contentDocument;
}
catch(e) {
G = document.embeds['bwsvg'].getSVGDocument();
}
if (!G)
{
window.setTimeout(arguments.callee, 1000);
}
else
{
/* find sizes */
width = svg.offsetWidth - 2;
height = svg.offsetHeight - 2;
data_wanted = Math.ceil(width / step);
/* prefill datasets */
for (var i = 0; i < data_wanted; i++)
{
data_udp[i] = 0;
data_tcp[i] = 0;
data_otr[i] = 0;
}
/* find svg elements */
line_udp = G.getElementById('udp');
line_tcp = G.getElementById('tcp');
line_otr = G.getElementById('other');
label_25 = G.getElementById('label_25');
label_50 = G.getElementById('label_50');
label_75 = G.getElementById('label_75');
label_udp_cur = document.getElementById('lb_udp_cur');
label_udp_avg = document.getElementById('lb_udp_avg');
label_udp_peak = document.getElementById('lb_udp_peak');
label_tcp_cur = document.getElementById('lb_tcp_cur');
label_tcp_avg = document.getElementById('lb_tcp_avg');
label_tcp_peak = document.getElementById('lb_tcp_peak');
label_otr_cur = document.getElementById('lb_otr_cur');
label_otr_avg = document.getElementById('lb_otr_avg');
label_otr_peak = document.getElementById('lb_otr_peak');
label_scale = document.getElementById('scale');
conn_table = document.getElementById('connections');
/* plot horizontal time interval lines */
for (var i = width % (step * 60); i < width; i += step * 60)
{
var line = G.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text = G.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(G.createTextNode(Math.round((width - i) / step / 60) + 'm'));
label_25.parentNode.appendChild(line);
label_25.parentNode.appendChild(text);
}
label_scale.innerHTML = String.format('<%:(%d minute window, %d second interval)%>', data_wanted / 60, 3);
/* render datasets, start update interval */
XHR.poll(3, '<%=build_url("admin/status/realtime/connections_status")%>', null,
function(x, json)
{
var rows = [];
var conn = json.connections;
var lookup_queue = [ ];
conn.sort(function(a, b) {
return b.bytes - a.bytes;
});
for (var i = 0; i < conn.length; i++)
{
var c = conn[i];
if ((c.src == '127.0.0.1' && c.dst == '127.0.0.1') ||
(c.src == '::1' && c.dst == '::1'))
continue;
if (!dns_cache[c.src])
lookup_queue.push(c.src);
if (!dns_cache[c.dst])
lookup_queue.push(c.dst);
var src = dns_cache[c.src] || (c.layer3 == 'ipv6' ? '[' + c.src + ']' : c.src);
var dst = dns_cache[c.dst] || (c.layer3 == 'ipv6' ? '[' + c.dst + ']' : c.dst);
rows.push([
c.layer3.toUpperCase(),
c.layer4.toUpperCase(),
src + ':' + c.sport,
dst + ':' + c.dport,
'%1024.2mB (%d <%:Pkts.%>)'.format(c.bytes, c.packets)
]);
}
cbi_update_table(conn_table, rows, '<em><%:No information available%></em>');
if (lookup_queue.length > 0)
XHR.get('<%=build_url("admin/status/nameinfo")%>/' + lookup_queue.slice(0, 100).join('/'), null,
function(x, json)
{
for (var addr in json)
dns_cache[addr] = json[addr];
}
);
var data = json.statistics;
var data_max = 0;
var data_scale = 0;
var data_udp_avg = 0;
var data_tcp_avg = 0;
var data_otr_avg = 0;
var data_udp_peak = 0;
var data_tcp_peak = 0;
var data_otr_peak = 0;
for (var i = data_stamp ? 0 : 1; i < data.length; i++)
{
/* skip overlapping entries */
if (data[i][TIME] <= data_stamp)
continue;
data_udp.push(data[i][UDP]);
data_tcp.push(data[i][TCP]);
data_otr.push(data[i][OTHER]);
}
/* cut off outdated entries */
data_udp = data_udp.slice(data_udp.length - data_wanted, data_udp.length);
data_tcp = data_tcp.slice(data_tcp.length - data_wanted, data_tcp.length);
data_otr = data_otr.slice(data_otr.length - data_wanted, data_otr.length);
/* find peak */
for (var i = 0; i < data_udp.length; i++)
{
data_max = Math.max(data_max, data_udp[i]);
data_max = Math.max(data_max, data_tcp[i]);
data_max = Math.max(data_max, data_otr[i]);
data_udp_peak = Math.max(data_udp_peak, data_udp[i]);
data_tcp_peak = Math.max(data_tcp_peak, data_tcp[i]);
data_otr_peak = Math.max(data_otr_peak, data_otr[i]);
if (i > 0)
{
data_udp_avg = (data_udp_avg + data_udp[i]) / 2;
data_tcp_avg = (data_tcp_avg + data_tcp[i]) / 2;
data_otr_avg = (data_otr_avg + data_otr[i]) / 2;
}
else
{
data_udp_avg = data_udp[i];
data_tcp_avg = data_tcp[i];
data_otr_avg = data_otr[i];
}
}
/* remember current timestamp, calculate horizontal scale */
data_stamp = data[data.length-1][TIME];
data_scale = height / (data_max * 1.1);
/* plot data */
var pt_udp = '0,' + height;
var pt_tcp = '0,' + height;
var pt_otr = '0,' + height;
var y_udp = 0;
var y_tcp = 0;
var y_otr = 0;
for (var i = 0; i < data_udp.length; i++)
{
var x = i * step;
y_udp = height - Math.floor(data_udp[i] * data_scale);
y_tcp = height - Math.floor(data_tcp[i] * data_scale);
y_otr = height - Math.floor(data_otr[i] * data_scale);
pt_udp += ' ' + x + ',' + y_udp;
pt_tcp += ' ' + x + ',' + y_tcp;
pt_otr += ' ' + x + ',' + y_otr;
}
pt_udp += ' ' + width + ',' + y_udp + ' ' + width + ',' + height;
pt_tcp += ' ' + width + ',' + y_tcp + ' ' + width + ',' + height;
pt_otr += ' ' + width + ',' + y_otr + ' ' + width + ',' + height;
var order = [
[ line_udp, data_udp[data_udp.length-1] ],
[ line_tcp, data_tcp[data_tcp.length-1] ],
[ line_otr, data_otr[data_otr.length-1] ]
];
order.sort(function(a, b) { return b[1] - a[1] });
for (var i = 0; i < order.length; i++)
order[i][0].parentNode.appendChild(order[i][0]);
line_udp.setAttribute('points', pt_udp);
line_tcp.setAttribute('points', pt_tcp);
line_otr.setAttribute('points', pt_otr);
label_25.firstChild.data = Math.floor(1.1 * 0.25 * data_max);
label_50.firstChild.data = Math.floor(1.1 * 0.50 * data_max);
label_75.firstChild.data = Math.floor(1.1 * 0.75 * data_max);
label_udp_cur.innerHTML = Math.floor(data_udp[data_udp.length-1]);
label_tcp_cur.innerHTML = Math.floor(data_tcp[data_tcp.length-1]);
label_otr_cur.innerHTML = Math.floor(data_otr[data_otr.length-1]);
label_udp_avg.innerHTML = Math.floor(data_udp_avg);
label_tcp_avg.innerHTML = Math.floor(data_tcp_avg);
label_otr_avg.innerHTML = Math.floor(data_otr_avg);
label_udp_peak.innerHTML = Math.floor(data_udp_peak);
label_tcp_peak.innerHTML = Math.floor(data_tcp_peak);
label_otr_peak.innerHTML = Math.floor(data_otr_peak);
}
);
XHR.run();
}
}, 1000
);
//]]></script>
<h2 name="content"><%:Realtime Connections%></h2>
<div class="cbi-map-descr"><%:This page gives an overview over currently active network connections.%></div>
<fieldset class="cbi-section" id="cbi-table-table">
<legend><%:Active Connections%></legend>
<embed id="bwsvg" style="width:100%; height:300px; border:1px solid #000000; background-color:#FFFFFF" src="<%=resource%>/connections.svg" />
<div style="text-align:right"><small id="scale">-</small></div>
<br />
<div class="table">
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid blue"><%:UDP:%></strong></div>
<div class="td" id="lb_udp_cur">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="lb_udp_avg">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="lb_udp_peak">0</div>
</div>
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid green"><%:TCP:%></strong></div>
<div class="td" id="lb_tcp_cur">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="lb_tcp_avg">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="lb_tcp_peak">0</div>
</div>
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid red"><%:Other:%></strong></div>
<div class="td" id="lb_otr_cur">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="lb_otr_avg">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="lb_otr_peak">0</div>
</div>
</div>
<br />
<div class="cbi-section-node">
<div class="table" id="connections">
<div class="tr table-titles">
<div class="th col-2 hide-xs"><%:Network%></div>
<div class="th col-2"><%:Protocol%></div>
<div class="th col-7"><%:Source%></div>
<div class="th col-7"><%:Destination%></div>
<div class="th col-4"><%:Transfer%></div>
</div>
<div class="tr placeholder">
<div class="td">
<em><%:Collecting data...%></em>
</div>
</div>
</div>
</div>
</fieldset>
<%+footer%>

View file

@ -1,12 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<h2 name="content"><%:Kernel Log%></h2>
<div id="content_syslog">
<textarea style="font-size: 12px;" readonly="readonly" wrap="off" rows="<%=dmesg:cmatch("\n")+2%>" id="syslog"><%=dmesg:pcdata()%></textarea>
</div>
<%+footer%>

View file

@ -1,467 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%
local fs = require "nixio.fs"
local ipc = require "luci.ip"
local util = require "luci.util"
local stat = require "luci.tools.status"
local ver = require "luci.version"
local has_ipv6 = fs.access("/proc/net/ipv6_route")
local has_dhcp = fs.access("/etc/config/dhcp")
local has_mptcp = (luci.sys.exec("sysctl -n net.mptcp.mptcp_enabled | tr -d '\n'")) or 0
local has_wifi = ((fs.stat("/etc/config/wireless", "size") or 0) > 0)
local sysinfo = luci.util.ubus("system", "info") or { }
local boardinfo = luci.util.ubus("system", "board") or { }
local unameinfo = nixio.uname() or { }
local meminfo = sysinfo.memory or {
total = 0,
free = 0,
buffered = 0,
shared = 0
}
local swapinfo = sysinfo.swap or {
total = 0,
free = 0
}
local has_dsl = fs.access("/etc/init.d/dsl_control")
if luci.http.formvalue("status") == "1" then
local ntm = require "luci.model.network".init()
local wan = ntm:get_wannet()
local wan6 = ntm:get_wan6net()
local conn_count = tonumber(
fs.readfile("/proc/sys/net/netfilter/nf_conntrack_count") or "") or 0
local conn_max = tonumber(luci.sys.exec(
"sysctl -n -e net.nf_conntrack_max net.ipv4.netfilter.ip_conntrack_max"
):match("%d+")) or 4096
local rv = {
uptime = sysinfo.uptime or 0,
localtime = os.date(),
loadavg = sysinfo.load or { 0, 0, 0 },
memory = meminfo,
swap = swapinfo,
connmax = conn_max,
conncount = conn_count,
wifinets = stat.wifi_networks()
}
if wan then
local dev = wan:get_interface()
local link = dev and ipc.link(dev:name())
rv.wan = {
ipaddr = wan:ipaddr(),
gwaddr = wan:gwaddr(),
netmask = wan:netmask(),
dns = wan:dnsaddrs(),
expires = wan:expires(),
uptime = wan:uptime(),
proto = wan:proto(),
i18n = wan:get_i18n(),
ifname = wan:ifname(),
link = wan:adminlink(),
mac = dev and dev:mac(),
type = dev and dev:type(),
name = dev and dev:get_i18n(),
ether = link and link.type == 1
}
end
if wan6 then
local dev = wan6:get_interface()
local link = dev and ipc.link(dev:name())
rv.wan6 = {
ip6addr = wan6:ip6addr(),
gw6addr = wan6:gw6addr(),
dns = wan6:dns6addrs(),
ip6prefix = wan6:ip6prefix(),
uptime = wan6:uptime(),
proto = wan6:proto(),
i18n = wan6:get_i18n(),
ifname = wan6:ifname(),
link = wan6:adminlink(),
mac = dev and dev:mac(),
type = dev and dev:type(),
name = dev and dev:get_i18n(),
ether = link and link.type == 1
}
end
if has_dsl then
local dsl_stat = luci.sys.exec("/etc/init.d/dsl_control lucistat")
local dsl_func = loadstring(dsl_stat)
if dsl_func then
rv.dsl = dsl_func()
end
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
function progressbar(v, m)
{
var vn = parseInt(v) || 0;
var mn = parseInt(m) || 100;
var pc = Math.floor((100 / mn) * vn);
return String.format(
'<div style="width:100%%; max-width:200px; position:relative; border:1px solid #999999">' +
'<div style="background-color:#CCCCCC; width:%d%%; height:15px">' +
'<div style="position:absolute; left:0; top:0; text-align:center; width:100%%; color:#000000">' +
'<small>%s / %s (%d%%)</small>' +
'</div>' +
'</div>' +
'</div>', pc, v, m, pc
);
}
function labelList(items, offset) {
var rv = [ ];
for (var i = offset || 0; i < items.length; i += 2) {
var label = items[i],
value = items[i+1];
if (value === undefined || value === null)
continue;
if (label)
rv.push(E('strong', [label, ': ']));
rv.push(value, E('br'));
}
return rv;
}
function renderBox(title, active, childs) {
childs = childs || [];
childs.unshift(E('span', labelList(arguments, 3)));
return E('div', { class: 'ifacebox' }, [
E('div', { class: 'ifacebox-head center ' + (active ? 'active' : '') },
E('strong', title)),
E('div', { class: 'ifacebox-body left' }, childs)
]);
}
function renderBadge(icon, title) {
return E('span', { class: 'ifacebadge' }, [
E('img', { src: icon, title: title || '' }),
E('span', labelList(arguments, 2))
]);
}
XHR.poll(5, '<%=REQUEST_URI%>', { status: 1 },
function(x, info)
{
<% if has_mptcp == 0 then %>
var us = document.getElementById('upstream_status_table');
while (us.lastElementChild)
us.removeChild(us.lastElementChild);
var ifc = info.wan || {};
us.appendChild(renderBox(
'<%:IPv4 Upstream%>',
(ifc.ifname && ifc.proto != 'none'),
[ E('div', {}, renderBadge(
'<%=resource%>/icons/%s.png'.format((ifc && ifc.type) ? ifc.type : 'ethernet_disabled'), null,
'<%:Device%>', ifc ? (ifc.name || ifc.ifname || '-') : '-',
'<%:MAC-Address%>', (ifc && ifc.ether) ? ifc.mac : null)) ],
'<%:Protocol%>', ifc.i18n || E('em', '<%:Not connected%>'),
'<%:Address%>', (ifc.ipaddr) ? ifc.ipaddr : '0.0.0.0',
'<%:Netmask%>', (ifc.netmask && ifc.netmask != ifc.ipaddr) ? ifc.netmask : '255.255.255.255',
'<%:Gateway%>', (ifc.gwaddr) ? ifc.gwaddr : '0.0.0.0',
'<%:DNS%> 1', (ifc.dns) ? ifc.dns[0] : null,
'<%:DNS%> 2', (ifc.dns) ? ifc.dns[1] : null,
'<%:DNS%> 3', (ifc.dns) ? ifc.dns[2] : null,
'<%:DNS%> 4', (ifc.dns) ? ifc.dns[3] : null,
'<%:DNS%> 5', (ifc.dns) ? ifc.dns[4] : null,
'<%:Expires%>', (ifc.expires > -1) ? '%t'.format(ifc.expires) : null,
'<%:Connected%>', (ifc.uptime > 0) ? '%t'.format(ifc.uptime) : null));
<% if has_ipv6 then %>
var ifc6 = info.wan6 || {};
us.appendChild(renderBox(
'<%:IPv6 Upstream%>',
(ifc6.ifname && ifc6.proto != 'none'),
[ E('div', {}, renderBadge(
'<%=resource%>/icons/%s.png'.format(ifc6.type || 'ethernet_disabled'), null,
'<%:Device%>', ifc6 ? (ifc6.name || ifc6.ifname || '-') : '-',
'<%:MAC-Address%>', (ifc6 && ifc6.ether) ? ifc6.mac : null)) ],
'<%:Protocol%>', ifc6.i18n ? (ifc6.i18n + (ifc6.proto === 'dhcp' && ifc6.ip6prefix ? '-PD' : '')) : E('em', '<%:Not connected%>'),
'<%:Prefix Delegated%>', ifc6.ip6prefix,
'<%:Address%>', (ifc6.ip6prefix) ? (ifc6.ip6addr || null) : (ifc6.ipaddr || '::'),
'<%:Gateway%>', (ifc6.gw6addr) ? ifc6.gw6addr : '::',
'<%:DNS%> 1', (ifc6.dns) ? ifc6.dns[0] : null,
'<%:DNS%> 2', (ifc6.dns) ? ifc6.dns[1] : null,
'<%:DNS%> 3', (ifc6.dns) ? ifc6.dns[2] : null,
'<%:DNS%> 4', (ifc6.dns) ? ifc6.dns[3] : null,
'<%:DNS%> 5', (ifc6.dns) ? ifc6.dns[4] : null,
'<%:Connected%>', (ifc6.uptime > 0) ? '%t'.format(ifc6.uptime) : null));
<% end %>
<% end %>
<% if has_dsl then %>
var ds = document.getElementById('dsl_status_table');
while (ds.lastElementChild)
ds.removeChild(ds.lastElementChild);
ds.appendChild(renderBox(
'<%:DSL Status%>',
(info.dsl.line_state === 'UP'), [ ],
'<%:Line State%>', '%s [0x%x]'.format(info.dsl.line_state, info.dsl.line_state_detail),
'<%:Line Mode%>', info.dsl.line_mode_s || '-',
'<%:Line Uptime%>', info.dsl.line_uptime_s || '-',
'<%:Annex%>', info.dsl.annex_s || '-',
'<%:Profile%>', info.dsl.profile_s || '-',
'<%:Data Rate%>', '%s/s / %s/s'.format(info.dsl.data_rate_down_s, info.dsl.data_rate_up_s),
'<%:Max. Attainable Data Rate (ATTNDR)%>', '%s/s / %s/s'.format(info.dsl.max_data_rate_down_s, info.dsl.max_data_rate_up_s),
'<%:Latency%>', '%s / %s'.format(info.dsl.latency_num_down, info.dsl.latency_num_up),
'<%:Line Attenuation (LATN)%>', '%d dB / %d dB'.format(info.dsl.line_attenuation_down, info.dsl.line_attenuation_up),
'<%:Signal Attenuation (SATN)%>', '%d dB / %d dB'.format(info.dsl.signal_attenuation_down, info.dsl.signal_attenuation_up),
'<%:Noise Margin (SNR)%>', '%d dB / %d dB'.format(info.dsl.noise_margin_down, info.dsl.noise_margin_up),
'<%:Aggregate Transmit Power(ACTATP)%>', '%d dB / %d dB'.format(info.dsl.actatp_down, info.dsl.actatp_up),
'<%:Forward Error Correction Seconds (FECS)%>', '%d / %d'.format(info.dsl.errors_fec_near, info.dsl.errors_fec_far),
'<%:Errored seconds (ES)%>', '%d / %d'.format(info.dsl.errors_es_near, info.dsl.errors_es_far),
'<%:Severely Errored Seconds (SES)%>', '%d / %d'.format(info.dsl.errors_ses_near, info.dsl.errors_ses_far),
'<%:Loss of Signal Seconds (LOSS)%>', '%d / %d'.format(info.dsl.errors_loss_near, info.dsl.errors_loss_far),
'<%:Unavailable Seconds (UAS)%>', '%d / %d'.format(info.dsl.errors_uas_near, info.dsl.errors_uas_far),
'<%:Header Error Code Errors (HEC)%>', '%d / %d'.format(info.dsl.errors_hec_near, info.dsl.errors_hec_far),
'<%:Non Pre-emtive CRC errors (CRC_P)%>', '%d / %d'.format(info.dsl.errors_crc_p_near, info.dsl.errors_crc_p_far),
'<%:Pre-emtive CRC errors (CRCP_P)%>', '%d / %d'.format(info.dsl.errors_crcp_p_near, info.dsl.errors_crcp_p_far),
'<%:ATU-C System Vendor ID%>', info.dsl.atuc_vendor_id,
'<%:Power Management Mode%>', info.dsl.power_mode_s));
<% end %>
<% if has_wifi then %>
var ws = document.getElementById('wifi_status_table');
if (ws)
{
while (ws.lastElementChild)
ws.removeChild(ws.lastElementChild);
for (var didx = 0; didx < info.wifinets.length; didx++)
{
var dev = info.wifinets[didx];
var net0 = (dev.networks && dev.networks[0]) ? dev.networks[0] : {};
var vifs = [];
for (var nidx = 0; nidx < dev.networks.length; nidx++)
{
var net = dev.networks[nidx];
var is_assoc = (net.bssid != '00:00:00:00:00:00' && net.channel && !net.disabled);
var icon;
if (net.disabled)
icon = "<%=resource%>/icons/signal-none.png";
else if (net.quality <= 0)
icon = "<%=resource%>/icons/signal-0.png";
else if (net.quality < 25)
icon = "<%=resource%>/icons/signal-0-25.png";
else if (net.quality < 50)
icon = "<%=resource%>/icons/signal-25-50.png";
else if (net.quality < 75)
icon = "<%=resource%>/icons/signal-50-75.png";
else
icon = "<%=resource%>/icons/signal-75-100.png";
vifs.push(renderBadge(
icon,
'<%:Signal%>: %d dBm / <%:Quality%>: %d%%'.format(net.signal, net.quality),
'<%:SSID%>', E('a', { href: net.link }, [ net.ssid || '?' ]),
'<%:Mode%>', net.mode,
'<%:BSSID%>', is_assoc ? (net.bssid || '-') : null,
'<%:Encryption%>', is_assoc ? net.encryption : null,
'<%:Associations%>', is_assoc ? (net.num_assoc || '-') : null,
null, is_assoc ? null : E('em', net.disabled ? '<%:Wireless is disabled%>' : '<%:Wireless is not associated%>')));
}
ws.appendChild(renderBox(
dev.device, dev.up || net0.up,
[ E('div', vifs) ],
'<%:Type%>', dev.name.replace(/^Generic | Wireless Controller .+$/g, ''),
'<%:Channel%>', net0.channel ? '%d (%.3f <%:GHz%>)'.format(net0.channel, net0.frequency) : '-',
'<%:Bitrate%>', net0.bitrate ? '%d <%:Mbit/s%>'.format(net0.bitrate) : '-'));
}
if (!ws.lastElementChild)
ws.appendChild(E('<em><%:No information available%></em>'));
}
<% end %>
var e;
if (e = document.getElementById('localtime'))
e.innerHTML = info.localtime;
if (e = document.getElementById('uptime'))
e.innerHTML = String.format('%t', info.uptime);
if (e = document.getElementById('loadavg'))
e.innerHTML = String.format(
'%.02f, %.02f, %.02f',
info.loadavg[0] / 65535.0,
info.loadavg[1] / 65535.0,
info.loadavg[2] / 65535.0
);
if (e = document.getElementById('memtotal'))
e.innerHTML = progressbar(
((info.memory.free + info.memory.buffered) / 1024) + " <%:kB%>",
(info.memory.total / 1024) + " <%:kB%>"
);
if (e = document.getElementById('memfree'))
e.innerHTML = progressbar(
(info.memory.free / 1024) + " <%:kB%>",
(info.memory.total / 1024) + " <%:kB%>"
);
if (e = document.getElementById('membuff'))
e.innerHTML = progressbar(
(info.memory.buffered / 1024) + " <%:kB%>",
(info.memory.total / 1024) + " <%:kB%>"
);
if (e = document.getElementById('swaptotal'))
e.innerHTML = progressbar(
(info.swap.free / 1024) + " <%:kB%>",
(info.swap.total / 1024) + " <%:kB%>"
);
if (e = document.getElementById('swapfree'))
e.innerHTML = progressbar(
(info.swap.free / 1024) + " <%:kB%>",
(info.swap.total / 1024) + " <%:kB%>"
);
if (e = document.getElementById('conns'))
e.innerHTML = progressbar(info.conncount, info.connmax);
}
);
//]]></script>
<h2 name="content"><%:Status%></h2>
<div class="cbi-section">
<h3><%:System%></h3>
<div class="table" width="100%">
<div class="tr"><div class="td left" width="33%"><%:Hostname%></div><div class="td left"><%=luci.sys.hostname() or "?"%></div></div>
<div class="tr"><div class="td left" width="33%"><%:Model%></div><div class="td left"><%=pcdata(boardinfo.model or "?")%></div></div>
<div class="tr"><div class="td left" width="33%"><%:Architecture%></div><div class="td left"><%=pcdata(boardinfo.system or "?")%></div></div>
<div class="tr"><div class="td left" width="33%"><%:Firmware Version%></div><div class="td left">
<%=pcdata(ver.distname)%> <%=pcdata(ver.distversion)%> /
<%=pcdata(ver.luciname)%> (<%=pcdata(ver.luciversion)%>)
</div></div>
<div class="tr"><div class="td left" width="33%"><%:Kernel Version%></div><div class="td left"><%=unameinfo.release or "?"%></div></div>
<div class="tr"><div class="td left" width="33%"><%:Local Time%></div><div class="td left" id="localtime">-</div></div>
<div class="tr"><div class="td left" width="33%"><%:Uptime%></div><div class="td left" id="uptime">-</div></div>
<div class="tr"><div class="td left" width="33%"><%:Load Average%></div><div class="td left" id="loadavg">-</div></div>
</div>
</div>
<div class="cbi-section">
<h3><%:Memory%></h3>
<div class="table" width="100%">
<div class="tr"><div class="td left" width="33%"><%:Total Available%></div><div class="td left" id="memtotal">-</div></div>
<div class="tr"><div class="td left" width="33%"><%:Free%></div><div class="td left" id="memfree">-</div></div>
<div class="tr"><div class="td left" width="33%"><%:Buffered%></div><div class="td left" id="membuff">-</div></div>
</div>
</div>
<% if swapinfo.total > 0 then %>
<div class="cbi-section">
<h3><%:Swap%></h3>
<div class="table" width="100%">
<div class="tr"><div class="td left" width="33%"><%:Total Available%></div><div class="td left" id="swaptotal">-</div></div>
<div class="tr"><div class="td left" width="33%"><%:Free%></div><div class="td left" id="swapfree">-</div></div>
</div>
</div>
<% end %>
<div class="cbi-section">
<h3><%:Network%></h3>
<% if has_mptcp == 0 then %>
<div id="upstream_status_table" class="network-status-table">
<p><em><%:Collecting data...%></em></p>
</div>
<% end %>
<div class="table" width="100%">
<div class="tr"><div class="td left" width="33%"><%:Active Connections%></div><div class="td left" id="conns">-</div></div>
</div>
</div>
<%
if has_dhcp then
include("admin_network/lease_status")
end
%>
<% if has_dsl then %>
<div class="cbi-section">
<h3><%:DSL%></h3>
<div id="dsl_status_table" class="network-status-table">
<p><em><%:Collecting data...%></em></p>
</div>
</div>
<% end %>
<% if has_wifi then %>
<div class="cbi-section">
<h3><%:Wireless%></h3>
<div id="wifi_status_table" class="network-status-table">
<p><em><%:Collecting data...%></em></p>
</div>
</div>
<div class="cbi-section">
<h3><%:Associated Stations%></h3>
<%+admin_network/wifi_assoclist%>
</div>
<% end %>
<%-
local incdir = util.libpath() .. "/view/admin_status/index/"
if fs.access(incdir) then
local inc
for inc in fs.dir(incdir) do
if inc:match("%.htm$") then
include("admin_status/index/" .. inc:gsub("%.htm$", ""))
end
end
end
-%>
<%+footer%>

View file

@ -1,155 +0,0 @@
<%#
Copyright 2008-2009 Steven Barth <steven@midlink.org>
Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
require "luci.sys.iptparser"
local wba = require "luci.tools.webadmin"
local fs = require "nixio.fs"
local io = require "io"
local has_ip6tables = fs.access("/usr/sbin/ip6tables")
local mode = 4
if has_ip6tables then
mode = luci.dispatcher.context.requestpath
mode = tonumber(mode[#mode] ~= "iptables" and mode[#mode]) or 4
end
local ipt = luci.sys.iptparser.IptParser(mode)
local rowcnt = 1
function rowstyle()
rowcnt = rowcnt + 1
return (rowcnt % 2) + 1
end
function link_target(t,c)
if ipt:is_custom_target(c) then
return '<a href="#rule_%s_%s">%s</a>' %{ t:lower(), c, c }
end
return c
end
function link_iface(i)
local net = wba.iface_get_network(i)
if net and i ~= "lo" then
return '<a href="%s">%s</a>' %{
url("admin/network/network", net), i
}
end
return i
end
local tables = { "Filter", "NAT", "Mangle", "Raw" }
if mode == 6 then
tables = { "Filter", "Mangle", "Raw" }
local ok, lines = pcall(io.lines, "/proc/net/ip6_tables_names")
if ok and lines then
local line
for line in lines do
if line == "nat" then
tables = { "Filter", "NAT", "Mangle", "Raw" }
end
end
end
end
-%>
<%+header%>
<style type="text/css">
span:target {
color: blue;
text-decoration: underline;
}
</style>
<h2 name="content"><%:Firewall Status%></h2>
<% if has_ip6tables then %>
<ul class="cbi-tabmenu">
<li class="cbi-tab<%= mode ~= 4 and "-disabled" %>"><a href="<%=url("admin/status/iptables/4")%>"><%:IPv4 Firewall%></a></li>
<li class="cbi-tab<%= mode ~= 6 and "-disabled" %>"><a href="<%=url("admin/status/iptables/6")%>"><%:IPv6 Firewall%></a></li>
</ul>
<% end %>
<div class="cbi-map" style="position: relative">
<form method="post" action="<%=url("admin/status/iptables_action")%>" style="position: absolute; right: 0">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="family" value="<%=mode%>" />
<input type="submit" class="cbi-button" name="zero" value="<%:Reset Counters%>" />
<input type="submit" class="cbi-button" name="restart" value="<%:Restart Firewall%>" />
</form>
<div class="cbi-section">
<% for _, tbl in ipairs(tables) do chaincnt = 0 %>
<h3><%:Table%>: <%=tbl%></h3>
<% for _, chain in ipairs(ipt:chains(tbl)) do
rowcnt = 0
chaincnt = chaincnt + 1
chaininfo = ipt:chain(tbl, chain)
%>
<h4 id="rule_<%=tbl:lower()%>_<%=chain%>">
<%:Chain%> <em><%=chain%></em>
(<%- if chaininfo.policy then -%>
<%:Policy%>: <em><%=chaininfo.policy%></em>, <%:Packets%>: <%=chaininfo.packets%>, <%:Traffic%>: <%=wba.byte_format(chaininfo.bytes)-%>
<%- else -%>
<%:References%>: <%=chaininfo.references-%>
<%- end -%>)
</h4>
<div class="cbi-section-node">
<div class="table" style="font-size:90%">
<div class="tr table-titles cbi-rowstyle-<%=rowstyle()%>">
<div class="th hide-xs"><%:Pkts.%></div>
<div class="th nowrap"><%:Traffic%></div>
<div class="th col-5"><%:Target%></div>
<div class="th"><%:Prot.%></div>
<div class="th"><%:In%></div>
<div class="th"><%:Out%></div>
<div class="th"><%:Source%></div>
<div class="th"><%:Destination%></div>
<div class="th col-9 hide-xs"><%:Options%></div>
</div>
<% for _, rule in ipairs(ipt:find({table=tbl, chain=chain})) do %>
<div class="tr cbi-rowstyle-<%=rowstyle()%>">
<div class="td"><%=rule.packets%></div>
<div class="td nowrap"><%=wba.byte_format(rule.bytes)%></div>
<div class="td col-5"><%=rule.target and link_target(tbl, rule.target) or "-"%></div>
<div class="td"><%=rule.protocol%></div>
<div class="td"><%=link_iface(rule.inputif)%></div>
<div class="td"><%=link_iface(rule.outputif)%></div>
<div class="td"><%=rule.source%></div>
<div class="td"><%=rule.destination%></div>
<div class="td col-9 hide-xs"><%=#rule.options > 0 and luci.util.pcdata(table.concat(rule.options, " ")) or "-"%></div>
</div>
<% end %>
<% if rowcnt == 1 then %>
<div class="tr cbi-rowstyle-<%=rowstyle()%>">
<div class="td" colspan="9"><em><%:No rules in this chain%></em></div>
</div>
<% end %>
</div>
</div>
<% end %>
<% if chaincnt == 0 then %>
<em><%:No chains in this table%></em>
<% end %>
<br /><br />
<% end %>
</div>
</div>
<%+footer%>

View file

@ -1,285 +0,0 @@
<%#
Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
var bwxhr = new XHR();
var G;
var TIME = 0;
var L01 = 1;
var L05 = 2;
var L15 = 3;
var width = 760;
var height = 300;
var step = 5;
var data_wanted = Math.floor(width / step);
var data_fill = 0;
var data_stamp = 0;
var data_01 = [ ];
var data_05 = [ ];
var data_15 = [ ];
var line_01;
var line_05;
var line_15;
var label_25;
var label_050;
var label_75;
var label_01_cur;
var label_01_avg;
var label_01_peak;
var label_05_cur;
var label_05_avg;
var label_05_peak;
var label_15_cur;
var label_15_avg;
var label_15_peak;
var label_scale;
/* wait for SVG */
window.setTimeout(
function() {
var svg = document.getElementById('bwsvg');
try {
G = svg.getSVGDocument
? svg.getSVGDocument() : svg.contentDocument;
}
catch(e) {
G = document.embeds['bwsvg'].getSVGDocument();
}
if (!G)
{
window.setTimeout(arguments.callee, 1000);
}
else
{
/* find sizes */
width = svg.offsetWidth - 2;
height = svg.offsetHeight - 2;
data_wanted = Math.ceil(width / step);
/* prefill datasets */
for (var i = 0; i < data_wanted; i++)
{
data_01[i] = 0;
data_05[i] = 0;
data_15[i] = 0;
}
/* find svg elements */
line_01 = G.getElementById('load01');
line_05 = G.getElementById('load05');
line_15 = G.getElementById('load15');
label_25 = G.getElementById('label_25');
label_50 = G.getElementById('label_50');
label_75 = G.getElementById('label_75');
label_01_cur = document.getElementById('lb_load01_cur');
label_01_avg = document.getElementById('lb_load01_avg');
label_01_peak = document.getElementById('lb_load01_peak');
label_05_cur = document.getElementById('lb_load05_cur');
label_05_avg = document.getElementById('lb_load05_avg');
label_05_peak = document.getElementById('lb_load05_peak');
label_15_cur = document.getElementById('lb_load15_cur');
label_15_avg = document.getElementById('lb_load15_avg');
label_15_peak = document.getElementById('lb_load15_peak');
label_scale = document.getElementById('scale');
/* plot horizontal time interval lines */
for (var i = width % (step * 60); i < width; i += step * 60)
{
var line = G.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text = G.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(G.createTextNode(Math.round((width - i) / step / 60) + 'm'));
label_25.parentNode.appendChild(line);
label_25.parentNode.appendChild(text);
}
label_scale.innerHTML = String.format('<%:(%d minute window, %d second interval)%>', data_wanted / 60, 3);
/* render datasets, start update interval */
XHR.poll(3, '<%=build_url("admin/status/realtime/load_status")%>', null,
function(x, data)
{
var data_max = 0;
var data_scale = 0;
var data_01_avg = 0;
var data_05_avg = 0;
var data_15_avg = 0;
var data_01_peak = 0;
var data_05_peak = 0;
var data_15_peak = 0;
for (var i = data_stamp ? 0 : 1; i < data.length; i++)
{
/* skip overlapping entries */
if (data[i][TIME] <= data_stamp)
continue;
data_01.push(data[i][L01]);
data_05.push(data[i][L05]);
data_15.push(data[i][L15]);
}
/* cut off outdated entries */
data_01 = data_01.slice(data_01.length - data_wanted, data_01.length);
data_05 = data_05.slice(data_05.length - data_wanted, data_05.length);
data_15 = data_15.slice(data_15.length - data_wanted, data_15.length);
/* find peak */
for (var i = 0; i < data_01.length; i++)
{
data_max = Math.max(data_max, data_01[i]);
data_max = Math.max(data_max, data_05[i]);
data_max = Math.max(data_max, data_15[i]);
data_01_peak = Math.max(data_01_peak, data_01[i]);
data_05_peak = Math.max(data_05_peak, data_05[i]);
data_15_peak = Math.max(data_15_peak, data_15[i]);
if (i > 0)
{
data_01_avg = (data_01_avg + data_01[i]) / 2;
data_05_avg = (data_05_avg + data_05[i]) / 2;
data_15_avg = (data_15_avg + data_15[i]) / 2;
}
else
{
data_01_avg = data_01[i];
data_05_avg = data_05[i];
data_15_avg = data_15[i];
}
}
/* remember current timestamp, calculate horizontal scale */
data_stamp = data[data.length-1][TIME];
data_scale = height / (data_max * 1.1);
/* plot data */
var pt_01 = '0,' + height;
var pt_05 = '0,' + height;
var pt_15 = '0,' + height;
var y_01 = 0;
var y_05 = 0;
var y_15 = 0;
for (var i = 0; i < data_01.length; i++)
{
var x = i * step;
y_01 = height - Math.floor(data_01[i] * data_scale);
y_05 = height - Math.floor(data_05[i] * data_scale);
y_15 = height - Math.floor(data_15[i] * data_scale);
pt_01 += ' ' + x + ',' + y_01;
pt_05 += ' ' + x + ',' + y_05;
pt_15 += ' ' + x + ',' + y_15;
}
pt_01 += ' ' + width + ',' + y_01 + ' ' + width + ',' + height;
pt_05 += ' ' + width + ',' + y_05 + ' ' + width + ',' + height;
pt_15 += ' ' + width + ',' + y_15 + ' ' + width + ',' + height;
line_01.setAttribute('points', pt_01);
line_05.setAttribute('points', pt_05);
line_15.setAttribute('points', pt_15);
label_25.firstChild.data = (1.1 * 0.25 * data_max / 100).toFixed(2);
label_50.firstChild.data = (1.1 * 0.50 * data_max / 100).toFixed(2);
label_75.firstChild.data = (1.1 * 0.75 * data_max / 100).toFixed(2);
label_01_cur.innerHTML = (data_01[data_01.length-1] / 100).toFixed(2);
label_05_cur.innerHTML = (data_05[data_05.length-1] / 100).toFixed(2);
label_15_cur.innerHTML = (data_15[data_15.length-1] / 100).toFixed(2);
label_01_avg.innerHTML = (data_01_avg / 100).toFixed(2);
label_05_avg.innerHTML = (data_05_avg / 100).toFixed(2);
label_15_avg.innerHTML = (data_15_avg / 100).toFixed(2);
label_01_peak.innerHTML = (data_01_peak / 100).toFixed(2);
label_05_peak.innerHTML = (data_05_peak / 100).toFixed(2);
label_15_peak.innerHTML = (data_15_peak / 100).toFixed(2);
}
);
XHR.run();
}
}, 1000
);
//]]></script>
<h2 name="content"><%:Realtime Load%></h2>
<embed id="bwsvg" style="width:100%; height:300px; border:1px solid #000000; background-color:#FFFFFF" src="<%=resource%>/load.svg" />
<div style="text-align:right"><small id="scale">-</small></div>
<br />
<div class="table" style="width:100%; table-layout:fixed" cellspacing="5">
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid #ff0000; white-space:nowrap"><%:1 Minute Load:%></strong></div>
<div class="td" id="lb_load01_cur">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="lb_load01_avg">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="lb_load01_peak">0</div>
</div>
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid #ff6600; white-space:nowrap"><%:5 Minute Load:%></strong></div>
<div class="td" id="lb_load05_cur">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="lb_load05_avg">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="lb_load05_peak">0</div>
</div>
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid #ffaa00; white-space:nowrap"><%:15 Minute Load:%></strong></div>
<div class="td" id="lb_load15_cur">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="lb_load15_avg">0</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="lb_load15_peak">0</div>
</div>
</div>
<%+footer%>

View file

@ -1,156 +0,0 @@
<%#
Copyright 2008-2009 Steven Barth <steven@midlink.org>
Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
require "luci.tools.webadmin"
require "nixio.fs"
local ip = require "luci.ip"
local style = true
local _, v
local rtn = {
[255] = "local",
[254] = "main",
[253] = "default",
[0] = "unspec"
}
if nixio.fs.access("/etc/iproute2/rt_tables") then
local ln
for ln in io.lines("/etc/iproute2/rt_tables") do
local i, n = ln:match("^(%d+)%s+(%S+)")
if i and n then
rtn[tonumber(i)] = n
end
end
end
-%>
<%+header%>
<div class="cbi-map" id="cbi-network">
<h2 name="content"><%:Routes%></h2>
<div class="cbi-map-descr"><%:The following rules are currently active on this system.%></div>
<div class="cbi-section">
<legend>ARP</legend>
<div class="cbi-section-node">
<div class="table">
<div class="tr table-titles">
<div class="th"><%_<abbr title="Internet Protocol Version 4">IPv4</abbr>-Address%></div>
<div class="th"><%_<abbr title="Media Access Control">MAC</abbr>-Address%></div>
<div class="th"><%:Interface%></div>
</div>
<%
for _, v in ipairs(ip.neighbors({ family = 4 })) do
if v.mac then
%>
<div class="tr cbi-rowstyle-<%=(style and 1 or 2)%>">
<div class="td"><%=v.dest%></div>
<div class="td"><%=v.mac%></div>
<div class="td"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></div>
</div>
<%
style = not style
end
end
%>
</div>
</div>
</div>
<div class="cbi-section">
<legend><%_Active <abbr title="Internet Protocol Version 4">IPv4</abbr>-Routes%></legend>
<div class="cbi-section-node">
<div class="table">
<div class="tr table-titles">
<div class="th"><%:Network%></div>
<div class="th"><%:Target%></div>
<div class="th"><%_<abbr title="Internet Protocol Version 4">IPv4</abbr>-Gateway%></div>
<div class="th"><%:Metric%></div>
<div class="th"><%:Table%></div>
</div>
<% for _, v in ipairs(ip.routes({ family = 4, type = 1 })) do %>
<div class="tr cbi-rowstyle-<%=(style and 1 or 2)%>">
<div class="td"><%=luci.tools.webadmin.iface_get_network(v.dev) or v.dev%></div>
<div class="td"><%=v.dest%></div>
<div class="td"><%=v.gw or "-"%></div>
<div class="td"><%=v.metric or 0%></div>
<div class="td"><%=rtn[v.table] or v.table%></div>
</div>
<% style = not style end %>
</div>
</div>
</div>
<%
if nixio.fs.access("/proc/net/ipv6_route") then
style = true
%>
<div class="cbi-section">
<legend><%_Active <abbr title="Internet Protocol Version 6">IPv6</abbr>-Routes%></legend>
<div class="cbi-section-node">
<div class="table">
<div class="tr table-titles">
<div class="th"><%:Network%></div>
<div class="th"><%:Target%></div>
<div class="th"><%:Source%></div>
<div class="th"><%:Metric%></div>
<div class="th"><%:Table%></div>
</div>
<%
for _, v in ipairs(ip.routes({ family = 6, type = 1 })) do
if v.dest and not v.dest:is6linklocal() then
%>
<div class="tr cbi-rowstyle-<%=(style and 1 or 2)%>">
<div class="td"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></div>
<div class="td"><%=v.dest%></div>
<div class="td"><%=v.from%></div>
<div class="td"><%=v.metric or 0%></div>
<div class="td"><%=rtn[v.table] or v.table%></div>
</div>
<%
style = not style
end
end
%>
</div>
</div>
</div>
<div class="cbi-section">
<legend><%:IPv6 Neighbours%></legend>
<div class="cbi-section-node">
<div class="table">
<div class="tr table-titles">
<div class="th"><%:IPv6-Address%></div>
<div class="th"><%:MAC-Address%></div>
<div class="th"><%:Interface%></div>
</div>
<%
for _, v in ipairs(ip.neighbors({ family = 6 })) do
if v.dest and not v.dest:is6linklocal() and v.mac then
%>
<div class="tr cbi-rowstyle-<%=(style and 1 or 2)%>">
<div class="td"><%=v.dest%></div>
<div class="td"><%=v.mac%></div>
<div class="td"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></div>
</div>
<%
style = not style
end
end
%>
</div>
</div>
</div>
<% end %>
</div>
<%+footer%>

View file

@ -1,12 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<h2 name="content"><%:System Log%></h2>
<div id="content_syslog">
<textarea style="font-size: 12px;" readonly="readonly" wrap="off" rows="<%=syslog:cmatch("\n")+2%>" id="syslog"><%=syslog:pcdata()%></textarea>
</div>
<%+footer%>

View file

@ -1,371 +0,0 @@
<%#
Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
local ntm = require "luci.model.network".init()
local dev
local devices = { }
for _, dev in luci.util.vspairs(luci.sys.net.devices()) do
if dev:match("^wlan%d") or dev:match("^ath%d") or dev:match("^wl%d") then
devices[#devices+1] = dev
end
end
local curdev = luci.http.formvalue("dev") or devices[1]
-%>
<%+header%>
<script type="text/javascript">//<![CDATA[
var bwxhr = new XHR();
var G, G2;
var TIME = 0;
var RATE = 1;
var RSSI = 2;
var NOISE = 3;
var width = 760;
var height = 300;
var step = 5;
var data_wanted = Math.floor(width / step);
var data_fill = 0;
var data_stamp = 0;
var data_rssi = [ ];
var data_noise = [ ];
var data_rate = [ ];
var line_rssi;
var line_noise;
var line_rate;
var label_25, label_25_2;
var label_50, label_50_2;
var label_75, label_75_2;
var label_rssi_cur;
var label_rssi_avg;
var label_rssi_peak;
var label_noise_cur;
var label_noise_avg;
var label_noise_peak;
var label_rate_cur;
var label_rate_avg;
var label_rate_peak;
var label_scale;
/* wait for SVG */
window.setTimeout(
function() {
var svg = document.getElementById('iwsvg');
var svg2 = document.getElementById('iwsvg2');
try {
G = svg.getSVGDocument
? svg.getSVGDocument() : svg.contentDocument;
G2 = svg2.getSVGDocument
? svg2.getSVGDocument() : svg2.contentDocument;
}
catch(e) {
G = document.embeds['iwsvg'].getSVGDocument();
G2 = document.embeds['iwsvg2'].getSVGDocument();
}
if (!G || !G2)
{
window.setTimeout(arguments.callee, 1000);
}
else
{
/* find sizes */
width = svg.offsetWidth - 2;
height = svg.offsetHeight - 2;
data_wanted = Math.ceil(width / step);
/* prefill datasets */
for (var i = 0; i < data_wanted; i++)
{
data_rssi[i] = 0;
data_noise[i] = 0;
data_rate[i] = 0;
}
/* find svg elements */
line_rssi = G.getElementById('rssi');
line_noise = G.getElementById('noise');
line_rate = G2.getElementById('rate');
label_25 = G.getElementById('label_25');
label_50 = G.getElementById('label_50');
label_75 = G.getElementById('label_75');
label_25_2 = G2.getElementById('label_25');
label_50_2 = G2.getElementById('label_50');
label_75_2 = G2.getElementById('label_75');
label_rssi_cur = document.getElementById('rssi_bw_cur');
label_rssi_avg = document.getElementById('rssi_bw_avg');
label_rssi_peak = document.getElementById('rssi_bw_peak');
label_noise_cur = document.getElementById('noise_bw_cur');
label_noise_avg = document.getElementById('noise_bw_avg');
label_noise_peak = document.getElementById('noise_bw_peak');
label_rate_cur = document.getElementById('rate_bw_cur');
label_rate_avg = document.getElementById('rate_bw_avg');
label_rate_peak = document.getElementById('rate_bw_peak');
label_scale = document.getElementById('scale');
label_scale_2 = document.getElementById('scale2');
/* plot horizontal time interval lines */
for (var i = width % (step * 60); i < width; i += step * 60)
{
var line = G.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text = G.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(G.createTextNode(Math.round((width - i) / step / 60) + 'm'));
label_25.parentNode.appendChild(line);
label_25.parentNode.appendChild(text);
var line2 = G2.createElementNS('http://www.w3.org/2000/svg', 'line');
line2.setAttribute('x1', i);
line2.setAttribute('y1', 0);
line2.setAttribute('x2', i);
line2.setAttribute('y2', '100%');
line2.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text2 = G2.createElementNS('http://www.w3.org/2000/svg', 'text');
text2.setAttribute('x', i + 5);
text2.setAttribute('y', 15);
text2.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text2.appendChild(G.createTextNode(Math.round((width - i) / step / 60) + 'm'));
label_25_2.parentNode.appendChild(line2);
label_25_2.parentNode.appendChild(text2);
}
label_scale.innerHTML = String.format('<%:(%d minute window, %d second interval)%>', data_wanted / 60, 3);
label_scale_2.innerHTML = String.format('<%:(%d minute window, %d second interval)%>', data_wanted / 60, 3);
/* render datasets, start update interval */
XHR.poll(3, '<%=build_url("admin/status/realtime/wireless_status", curdev)%>', null,
function(x, data)
{
var noise_floor = 255;
var rate_floor = 60000;
for (var i = 0; i < data.length; i++) {
noise_floor = Math.min(noise_floor, data[i][NOISE]);
rate_floor = Math.min(rate_floor, data[i][RATE]);
}
noise_floor -= 5;
var data_max = 0;
var data_scale = 0;
var data_max_2 = 0;
var data_scale_2 = 0;
var data_rssi_avg = 0;
var data_noise_avg = 0;
var data_rate_avg = 0;
var data_rssi_peak = 0;
var data_noise_peak = 0;
var data_rate_peak = 0;
for (var i = data_stamp ? 0 : 1; i < data.length; i++)
{
/* skip overlapping entries */
if (data[i][TIME] <= data_stamp)
continue;
data_rssi.push(data[i][RSSI] - noise_floor);
data_noise.push(data[i][NOISE] - noise_floor);
data_rate.push(Math.floor(data[i][RATE] / 1000));
}
/* cut off outdated entries */
data_rssi = data_rssi.slice(data_rssi.length - data_wanted, data_rssi.length);
data_noise = data_noise.slice(data_noise.length - data_wanted, data_noise.length);
data_rate = data_rate.slice(data_rate.length - data_wanted, data_rate.length);
/* find peak */
for (var i = 0; i < data_rssi.length; i++)
{
data_max = Math.max(data_max, data_rssi[i]);
data_max_2 = Math.max(data_max_2, data_rate[i]);
data_rssi_peak = Math.max(data_rssi_peak, data_rssi[i]);
data_noise_peak = Math.max(data_noise_peak, data_noise[i]);
data_rate_peak = Math.max(data_rate_peak, data_rate[i]);
if (i > 0)
{
data_rssi_avg = (data_rssi_avg + data_rssi[i]) / 2;
data_noise_avg = (data_noise_avg + data_noise[i]) / 2;
data_rate_avg = (data_rate_avg + data_rate[i]) / 2;
}
else
{
data_rssi_avg = data_rssi[i];
data_noise_avg = data_noise[i];
data_rate_avg = data_rate[i];
}
}
/* remember current timestamp, calculate horizontal scale */
data_stamp = data[data.length-1][TIME];
data_scale = (height / (data_max * 1.1)).toFixed(1);
data_scale_2 = (height / (data_max_2 * 1.1)).toFixed(1);
/* plot data */
var pt_rssi = '0,' + height;
var pt_noise = '0,' + height;
var pt_rate = '0,' + height;
var y_rssi = 0;
var y_noise = 0;
var y_rate = 0;
for (var i = 0; i < data_rssi.length; i++)
{
var x = i * step;
y_rssi = height - Math.floor(data_rssi[i] * data_scale);
y_noise = height - Math.floor(data_noise[i] * data_scale);
y_rate = height - Math.floor(data_rate[i] * data_scale_2);
y_rssi -= Math.floor(y_rssi % (1/data_scale));
y_noise -= Math.floor(y_noise % (1/data_scale));
pt_rssi += ' ' + x + ',' + y_rssi;
pt_noise += ' ' + x + ',' + y_noise;
pt_rate += ' ' + x + ',' + y_rate;
}
pt_rssi += ' ' + width + ',' + y_rssi + ' ' + width + ',' + height;
pt_noise += ' ' + width + ',' + y_noise + ' ' + width + ',' + height;
pt_rate += ' ' + width + ',' + y_rate + ' ' + width + ',' + height;
line_rssi.setAttribute('points', pt_rssi);
line_noise.setAttribute('points', pt_noise);
line_rate.setAttribute('points', pt_rate);
function wireless_label(dbm, noise)
{
if (noise)
return String.format("%d <%:dBm%> (SNR %d <%:dB%>)", noise_floor + dbm - 255, dbm - noise);
else
return String.format("%d <%:dBm%>", noise_floor + dbm - 255);
}
function rate_label(mbit)
{
return String.format("%d <%:Mbit/s%>", mbit);
}
label_25.firstChild.data = wireless_label(1.1 * 0.25 * data_max);
label_50.firstChild.data = wireless_label(1.1 * 0.50 * data_max);
label_75.firstChild.data = wireless_label(1.1 * 0.75 * data_max);
label_25_2.firstChild.data = rate_label(1.1 * 0.25 * data_max_2);
label_50_2.firstChild.data = rate_label(1.1 * 0.50 * data_max_2);
label_75_2.firstChild.data = rate_label(1.1 * 0.75 * data_max_2);
label_rssi_cur.innerHTML = wireless_label(data_rssi[data_rssi.length-1], data_noise[data_noise.length-1]).nobr();
label_noise_cur.innerHTML = wireless_label(data_noise[data_noise.length-1]).nobr();
label_rssi_avg.innerHTML = wireless_label(data_rssi_avg, data_noise_avg).nobr();
label_noise_avg.innerHTML = wireless_label(data_noise_avg).nobr();
label_rssi_peak.innerHTML = wireless_label(data_rssi_peak, data_noise_peak).nobr();
label_noise_peak.innerHTML = wireless_label(data_noise_peak).nobr();
label_rate_cur.innerHTML = rate_label(data_rate[data_rate.length-1]);
label_rate_avg.innerHTML = rate_label(data_rate_avg);
label_rate_peak.innerHTML = rate_label(data_rate_peak);
}
);
XHR.run();
}
}, 1000
);
//]]></script>
<h2 name="content"><%:Realtime Wireless%></h2>
<ul class="cbi-tabmenu">
<% for _, dev in ipairs(devices) do %>
<li class="cbi-tab<%= dev == curdev and "" or "-disabled" %>"><a href="?dev=<%=pcdata(dev)%>"><%=pcdata(dev)%></a></li>
<% end %>
</ul>
<embed id="iwsvg" style="width:100%; height:300px; border:1px solid #000000; background-color:#FFFFFF" src="<%=resource%>/wireless.svg" />
<div style="text-align:right"><small id="scale">-</small></div>
<br />
<div class="table" style="width:100%; table-layout:fixed" cellspacing="5">
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid blue"><%:Signal:%></strong></div>
<div class="td" id="rssi_bw_cur">0 <%:dBm%></div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="rssi_bw_avg">0 <%:dBm%></div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="rssi_bw_peak">0 <%:dBm%></div>
</div>
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid red"><%:Noise:%></strong></div>
<div class="td" id="noise_bw_cur">0 <%:dBm%></div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="noise_bw_avg">0 <%:dBm%></div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="noise_bw_peak">0 <%:dBm%></div>
</div>
</div>
<br />
<embed id="iwsvg2" style="width:100%; height:300px; border:1px solid #000000; background-color:#FFFFFF" src="<%=resource%>/wifirate.svg" />
<div style="text-align:right"><small id="scale2">-</small></div>
<br />
<div class="table" style="width:100%; table-layout:fixed" cellspacing="5">
<div class="tr">
<div class="td" style="text-align:right; vertical-align:top"><strong style="border-bottom:2px solid green"><%:Phy Rate:%></strong></div>
<div class="td" id="rate_bw_cur">0 MBit/s</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Average:%></strong></div>
<div class="td" id="rate_bw_avg">0 MBit/s</div>
<div class="td" style="text-align:right; vertical-align:top"><strong><%:Peak:%></strong></div>
<div class="td" id="rate_bw_peak">0 MBit/s</div>
</div>
</div>
<%+footer%>

View file

@ -1,41 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<html>
<head>
<title><%=luci.sys.hostname()%> - <% if title then %><%=title%><% else %><%:Rebooting...%><% end %></title>
<link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" />
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
var interval = window.setInterval(function() {
var img = new Image();
img.onload = function() {
window.clearInterval(interval);
location.href = ('https:' == document.location.protocol ? 'https://' : 'http://') + '<%=addr or luci.http.getenv("SERVER_NAME")%>/';
};
img.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + '<%=addr or luci.http.getenv("SERVER_NAME")%><%=resource%>/icons/loading.gif?' + Math.random();
}, 5000);
//]]></script>
</head>
<body>
<div id="maincontainer">
<div id="maincontent">
<h2 name="content"><%:System%> - <% if title then %><%=title%><% else %><%:Rebooting...%><% end %></h2>
<fieldset class="cbi-section">
<p>
<% if msg then %><%=msg%><% else %><%:Changes applied.%><% end %>
</p>
<p>
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" />
<%:Waiting for changes to be applied...%>
</p>
</fieldset>
</div>
</div>
</body>
</html>

View file

@ -1,10 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<ul class="cbi-tabmenu">
<li class="cbi-tab-disabled"><a href="<%=url("admin/system/flashops")%>"><%:Actions%></a></li>
<li class="cbi-tab"><a href="#"><%:Configuration%></a></li>
</ul>

View file

@ -1,36 +0,0 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=url('admin/system/clock_status')%>', null,
function(x, rv)
{
var s = document.getElementById('<%=self.option%>-clock-status');
if (s)
{
s.innerHTML = rv.timestring || '?';
}
}
);
function sync_clock(btn)
{
btn.disabled = true;
btn.value = '<%:Synchronizing...%>';
(new XHR()).post('<%=url('admin/system/clock_status')%>',
{ token: '<%=token%>', set: Math.floor((new Date()).getTime() / 1000) },
function()
{
btn.disabled = false;
btn.value = '<%:Sync with browser%>';
}
);
return false;
}
//]]></script>
<span id="<%=self.option%>-clock-status"><em><%:Collecting data...%></em></span>
<input type="button" class="cbi-button cbi-button-apply" value="<%:Sync with browser%>" onclick="return sync_clock(this)" />
<%+cbi/valuefooter%>

View file

@ -1,94 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<h2 name="content"><%:Flash operations%></h2>
<ul class="cbi-tabmenu">
<li class="cbi-tab"><a href="#"><%:Actions%></a></li>
<li class="cbi-tab-disabled"><a href="<%=url('admin/system/flashops/backupfiles')%>"><%:Configuration%></a></li>
</ul>
<div class="cbi-section">
<h3><%:Backup%></h3>
<div class="cbi-section-descr"><%:Click "Generate archive" to download a tar archive of the current configuration files.%></div>
<div class="cbi-section-node">
<form class="inline" method="post" action="<%=url('admin/system/flashops/backup')%>">
<input type="hidden" name="token" value="<%=token%>" />
<div class="cbi-value<% if not reset_avail then %> cbi-value-last<% end %>">
<label class="cbi-value-title" for="image"><%:Download backup%>:</label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-action important" type="submit" name="backup" value="<%:Generate archive%>" />
</div>
</div>
</form>
</div>
<h3><%:Restore%></h3>
<div class="cbi-section-descr"><%:To restore configuration files, you can upload a previously generated backup archive here. To reset the firmware to its initial state, click "Perform reset" (only possible with squashfs images).%></div>
<div class="cbi-section-node">
<% if reset_avail then %>
<form class="inline" method="post" action="<%=url('admin/system/flashops/reset')%>">
<input type="hidden" name="token" value="<%=token%>" />
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title"><%:Reset to defaults%>:</label>
<div class="cbi-value-field">
<input onclick="return confirm('<%:Really reset all changes?%>')" class="cbi-button cbi-button-reset" type="submit" name="reset" value="<%:Perform reset%>" />
</div>
</div>
</form>
<% end %>
<form class="inline" method="post" action="<%=url('admin/system/flashops/restore')%>" enctype="multipart/form-data">
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title" for="archive"><%:Restore backup%>:</label>
<div class="cbi-value-field">
<input type="hidden" name="token" value="<%=token%>" />
<input type="file" name="archive" id="archive" />
<input type="submit" class="cbi-button cbi-button-action important" name="restore" value="<%:Upload archive...%>" />
<% if reset_avail then %>
<div class="cbi-value-description"><%:Custom files (certificates, scripts) may remain on the system. To prevent this, perform a factory-reset first.%></div>
<% end %>
</div>
</div>
</form>
<% if backup_invalid then %>
<div class="cbi-section-error"><%:The backup archive does not appear to be a valid gzip file.%></div>
<% end %>
</div>
</div>
<div class="cbi-section">
<h3><%:Flash new firmware image%></h3>
<% if upgrade_avail then %>
<form method="post" action="<%=url('admin/system/flashops/sysupgrade')%>" enctype="multipart/form-data">
<input type="hidden" name="token" value="<%=token%>" />
<div class="cbi-section-descr"><%:Upload a sysupgrade-compatible image here to replace the running firmware. Check "Keep settings" to retain the current configuration (requires a compatible firmware image).%></div>
<div class="cbi-section-node">
<div class="cbi-value">
<label class="cbi-value-title" for="keep"><%:Keep settings%>:</label>
<div class="cbi-value-field">
<input type="checkbox" name="keep" id="keep" checked="checked" />
</div>
</div>
<div class="cbi-value cbi-value-last<% if image_invalid then %> cbi-value-error<% end %>">
<label class="cbi-value-title" for="image"><%:Image%>:</label>
<div class="cbi-value-field">
<input type="file" name="image" id="image" />
<input type="submit" class="cbi-button cbi-button-action important" value="<%:Flash image...%>" />
</div>
</div>
</div>
<% if image_invalid then %>
<div class="cbi-section-error"><%:The uploaded image file does not contain a supported format. Make sure that you choose the generic image format for your platform. %></div>
<% end %>
</form>
<% else %>
<div class="cbi-section-descr"><%:Sorry, there is no sysupgrade support present; a new firmware image must be flashed manually. Please refer to the wiki for device specific install instructions.%></div>
<% end %>
</div>
<%+footer%>

View file

@ -1,10 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<ul class="cbi-tabmenu">
<li class="cbi-tab-disabled"><a href="<%=url("admin/system/packages")%>"><%:Actions%></a></li>
<li class="cbi-tab"><a href="#"><%:Configuration%></a></li>
</ul>

View file

@ -1,213 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2010 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
local opkg = require "luci.model.ipkg"
local fs = require "nixio.fs"
local wa = require "luci.tools.webadmin"
local rowcnt = 1
function rowstyle()
rowcnt = rowcnt + 1
return (rowcnt % 2) + 1
end
local fstat = fs.statvfs(opkg.overlay_root())
local space_total = fstat and fstat.blocks or 0
local space_free = fstat and fstat.bfree or 0
local space_used = space_total - space_free
local used_perc = math.floor(0.5 + ((space_total > 0) and ((100 / space_total) * space_used) or 100))
local free_byte = space_free * fstat.frsize
local filter = { }
local opkg_list = luci.model.ipkg.list_all
local querypat
if query and #query > 0 then
querypat = '*%s*' % query
opkg_list = luci.model.ipkg.find
end
local letterpat
if letter == 35 then
letterpat = "[^a-z]*"
else
letterpat = string.char(letter, 42) -- 'A' '*'
end
-%>
<%+header%>
<h2 name="content"><%:Software%></h2>
<div class="cbi-map">
<ul class="cbi-tabmenu">
<li class="cbi-tab"><a href="#"><%:Actions%></a></li>
<li class="cbi-tab-disabled"><a href="<%=REQUEST_URI%>/ipkg"><%:Configuration%></a></li>
</ul>
<form method="post" action="<%=REQUEST_URI%>">
<input type="hidden" name="exec" value="1" />
<input type="hidden" name="token" value="<%=token%>" />
<div class="cbi-section">
<div class="cbi-section-node">
<% if (install and next(install)) or (remove and next(remove)) or update or upgrade then %>
<div class="cbi-value">
<% if #stdout > 0 then %><pre><%=pcdata(stdout)%></pre><% end %>
<% if #stderr > 0 then %><pre class="error"><%=pcdata(stderr)%></pre><% end %>
</div>
<% end %>
<% if querypat then %>
<div class="cbi-value">
<%:Displaying only packages containing%> <strong>"<%=pcdata(query)%>"</strong>
<input type="button" onclick="location.href='?display=<%=luci.http.urlencode(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" />
<br style="clear:both" />
</div>
<% end %>
<% if no_lists or old_lists then %>
<div class="cbi-value">
<% if old_lists then %>
<%:Package lists are older than 24 hours%>
<% else %>
<%:No package lists available%>
<% end %>
<input type="submit" name="update" href="#" class="cbi-button cbi-button-apply" style="margin-left:3em" value="<%:Update lists%>" />
</div>
<% end %>
<div class="cbi-value cbi-value-last">
<%:Free space%>: <strong><%=(100-used_perc)%>%</strong> (<strong><%=wa.byte_format(free_byte)%></strong>)
<div style="margin:3px 0; width:300px; height:10px; border:1px solid #000000; background-color:#80C080">
<div style="background-color:#F08080; border-right:1px solid #000000; height:100%; width:<%=used_perc%>%">&#160;</div>
</div>
</div>
</div>
<br />
<div class="cbi-section-node">
<input type="hidden" name="display" value="<%=pcdata(display)%>" />
<div class="cbi-value">
<label class="cbi-value-title"><%:Download and install package%>:</label>
<div class="cbi-value-field">
<span><input type="text" name="url" size="30" value="" /></span>
<input class="cbi-button cbi-button-save" type="submit" name="go" value="<%:OK%>" />
</div>
</div>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title"><%:Filter%>:</label>
<div class="cbi-value-field">
<span><input type="text" name="query" size="20" value="<%=pcdata(query)%>" /></span>
<input type="submit" class="cbi-button cbi-button-action" name="search" value="<%:Find package%>" />
</div>
</div>
</div>
</div>
</form>
<h3><%:Status%></h3>
<ul class="cbi-tabmenu">
<li class="cbi-tab<% if display ~= "available" then %>-disabled<% end %>"><a href="?display=available&amp;query=<%=pcdata(query)%>"><%:Available packages%><% if query then %> (<%=pcdata(query)%>)<% end %></a></li>
<li class="cbi-tab<% if display ~= "installed" then %>-disabled<% end %>"><a href="?display=installed&amp;query=<%=pcdata(query)%>"><%:Installed packages%><% if query then %> (<%=pcdata(query)%>)<% end %></a></li>
</ul>
<% if display ~= "available" then %>
<div class="cbi-section">
<div class="cbi-section-node">
<div class="table">
<div class="tr cbi-section-table-titles">
<div class="th left"><%:Package name%></div>
<div class="th left"><%:Version%></div>
<div class="th cbi-section-actions">&#160;</div>
</div>
<% local empty = true; luci.model.ipkg.list_installed(querypat, function(n, v, s, d) empty = false; filter[n] = true %>
<div class="tr cbi-rowstyle-<%=rowstyle()%>">
<div class="td left"><%=luci.util.pcdata(n)%></div>
<div class="td left"><%=luci.util.pcdata(v)%></div>
<div class="td cbi-section-actions">
<form method="post" class="inline" action="<%=REQUEST_URI%>">
<input type="hidden" name="exec" value="1" />
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="remove" value="<%=pcdata(n)%>" />
<input class="cbi-button cbi-button-remove" type="submit" onclick="window.confirm('<%:Remove%> &quot;<%=luci.util.pcdata(n)%>&quot; ?') &#38;&#38; this.parentNode.submit(); return false" value="<%:Remove%>" />
</form>
</div>
</div>
<% end) %>
<% if empty then %>
<div class="tr cbi-section-table-row">
<div class="td left">&#160;</div>
<div class="td left"><em><%:none%></em></div>
<div class="td left"><em><%:none%></em></div>
</div>
<% end %>
</div>
</div>
</div>
<% else %>
<div class="cbi-section">
<% if not querypat then %>
<ul class="cbi-tabmenu" style="flex-wrap:wrap">
<% local i; for i = 65, 90 do %>
<li class="cbi-tab<% if letter ~= i then %>-disabled<% end %>"><a href="?display=available&amp;letter=<%=string.char(i)%>"><%=string.char(i)%></a></li>
<% end %>
<li class="cbi-tab<% if letter ~= 35 then %>-disabled<% end %>"><a href="?display=available&amp;letter=%23">#</a></li>
</ul>
<% end %>
<div class="cbi-section-node cbi-section-node-tabbed">
<div class="table">
<div class="tr cbi-section-table-titles">
<div class="th col-2 left"><%:Package name%></div>
<div class="th col-2 left"><%:Version%></div>
<div class="th col-1 center"><%:Size (.ipk)%></div>
<div class="th col-10 left"><%:Description%></div>
<div class="th cbi-section-actions">&#160;</div>
</div>
<% local empty = true; opkg_list(querypat or letterpat, function(n, v, s, d) if filter[n] then return end; empty = false %>
<div class="tr cbi-rowstyle-<%=rowstyle()%>">
<div class="td col-2 left"><%=luci.util.pcdata(n)%></div>
<div class="td col-2 left"><%=luci.util.pcdata(v)%></div>
<div class="td col-1 center"><%=luci.util.pcdata(s)%></div>
<div class="td col-10 left"><%=luci.util.pcdata(d)%></div>
<div class="td cbi-section-actions">
<form method="post" class="inline" action="<%=REQUEST_URI%>">
<input type="hidden" name="exec" value="1" />
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="install" value="<%=pcdata(n)%>" />
<input class="cbi-button cbi-button-apply" type="submit" onclick="window.confirm('<%:Install%> &quot;<%=luci.util.pcdata(n)%>&quot; ?') &#38;&#38; this.parentNode.submit(); return false" value="<%:Install%>" />
</form>
</div>
</div>
<% end) %>
<% if empty then %>
<div class="tr">
<div class="td left">&#160;</div>
<div class="td left"><em><%:none%></em></div>
<div class="td left"><em><%:none%></em></div>
<div class="td right"><em><%:none%></em></div>
<div class="td left"><em><%:none%></em></div>
</div>
<% end %>
</div>
</div>
</div>
<% end %>
</div>
<%+footer%>

View file

@ -1,62 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<h2 name="content"><%:Reboot%></h2>
<p><%:Reboots the operating system of your device%></p>
<%- local c = require("luci.model.uci").cursor():changes(); if c and next(c) then -%>
<p class="alert-message warning"><%:Warning: There are unsaved changes that will get lost on reboot!%></p>
<%- end -%>
<hr />
<input class="cbi-button cbi-button-action important" type="button" value="<%:Perform reboot%>" onclick="reboot(this)" />
<p class="alert-message notice reboot-message" style="display:none">
<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" />
<span><%:Device is rebooting...%></span>
</p>
<script type="text/javascript">//<![CDATA[
var tries = 0,
message = document.querySelector('p.reboot-message'),
label = message.querySelector('span');
function ok() {
window.location = '<%=url("admin")%>';
}
function check() {
window.setTimeout(ping, 5000);
}
function ping() {
var img = document.createElement('img');
img.onload = ok;
img.onerror = check;
img.src = '<%=resource%>/icons/loading.gif?' + Math.random();
if (tries++ >= 30) {
message.classList.remove('notice');
message.classList.add('warning');
label.innerHTML = '<%:Device unreachable! Still waiting for device...%>';
}
}
function reboot(button) {
button.style.display = 'none';
message.style.display = '';
label.innerHTML = '<%:Waiting for device...%>';
(new XHR()).post('<%=url("admin/system/reboot/call")%>', { token: '<%=token%>' }, check);
}
//]]></script>
<%+footer%>

View file

@ -1,59 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2009 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<h2 name="content"><%:Flash Firmware%> - <%:Verify%></h2>
<p>
<%_ The flash image was uploaded.
Below is the checksum and file size listed,
compare them with the original file to ensure data integrity.<br />
Click "Proceed" below to start the flash procedure. %>
<% if storage > 0 and size > storage then %>
<br /><br />
<div class="error"><%:It appears that you are trying to
flash an image that does not fit into the flash memory, please verify
the image file! %></div>
<% end %>
</p>
<fieldset class="cbi-section">
<ul>
<li><%:Checksum%><br />
<%:MD5%>: <code><%=checksum%></code><br />
<%:SHA256%>: <code><%=sha256ch%></code></li>
<li><%:Size%>: <%
local w = require "luci.tools.webadmin"
write(w.byte_format(size))
if storage > 0 then
write(luci.i18n.translatef(
" (%s available)",
w.byte_format(storage)
))
end
%></li>
<li><% if keep then %>
<%:Configuration files will be kept.%>
<% else %>
<%:Note: Configuration files will be erased.%>
<% end %></li>
</ul>
</fieldset>
<div class="cbi-page-actions right">
<form class="inline" action="<%=REQUEST_URI%>" method="post">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="step" value="2" />
<input type="hidden" name="keep" value="<%=keep and "1" or ""%>" />
<input class="cbi-button cbi-button-reset" name="cancel" type="submit" value="<%:Cancel%>" />
<input class="cbi-button cbi-button-apply" type="submit" value="<%:Proceed%>" />
</form>
</div>
<%+footer%>

View file

@ -1,81 +0,0 @@
<%#
Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<% export("uci_changelog", function(changes) -%>
<div class="cbi-section">
<strong><%:Legend:%></strong>
<div class="uci-change-legend">
<div class="uci-change-legend-label"><ins>&#160;</ins> <%:Section added%></div>
<div class="uci-change-legend-label"><del>&#160;</del> <%:Section removed%></div>
<div class="uci-change-legend-label"><var><ins>&#160;</ins></var> <%:Option changed%></div>
<div class="uci-change-legend-label"><var><del>&#160;</del></var> <%:Option removed%></div>
<br style="clear:both" />
</div>
<br />
<div class="uci-change-list"><%
local util = luci.util
local ret = { }
for r, tbl in pairs(changes) do
for s, os in pairs(tbl) do
-- section add
if os['.type'] and os['.type'] ~= "" then
ret[#ret+1] = "<ins>%s.%s=<strong>%s</strong>" %{ r, s, os['.type'] }
for o, v in util.kspairs(os) do
if o:sub(1,1) ~= "." then
if type(v) == "table" then
local i
for i = 1, #v do
ret[#ret+1] = "<br />%s.%s.%s+=<strong>%s</strong>"
%{ r, s, o, util.pcdata(v[i]) }
end
elseif v ~= "" then
ret[#ret+1] = "<br />%s.%s.%s=<strong>%s</strong>"
%{ r, s, o, util.pcdata(v) }
else
ret[#ret+1] = "<br /><del>%s.%s.<strong>%s</strong></del>" %{ r, s, o }
end
end
end
ret[#ret+1] = "</ins><br />"
-- section delete
elseif os['.type'] and os['.type'] == "" then
ret[#ret+1] = "<del>%s.<strong>%s</strong></del><br />" %{ r, s }
-- modifications
else
ret[#ret+1] = "<var>%s.%s<br />" %{ r, s }
for o, v in util.kspairs(os) do
if o:sub(1,1) ~= "." then
if v and #v > 0 then
ret[#ret+1] = "<ins>"
if type(v) == "table" then
local i
for i = 1, #v do
ret[#ret+1] = "%s.%s.%s+=<strong>%s</strong><br />"
%{ r, s, o, util.pcdata(v[i]) }
end
else
ret[#ret+1] = "%s.%s.%s=<strong>%s</strong><br />"
%{ r, s, o, util.pcdata(v) }
end
ret[#ret+1] = "</ins>"
else
ret[#ret+1] = "<del>%s.%s.<strong>%s</strong><br /></del>" %{ r, s, o }
end
end
end
ret[#ret+1] = "</var><br />"
end
end
end
write(table.concat(ret))
%></div>
</div>
<%- end) %>

View file

@ -1,45 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2018 Jo-Philipp Wich <jo@mein.io>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<%-
local node, redir_url = luci.dispatcher.lookup(luci.http.formvalue("redir"))
export("redirect", redir_url or url("admin/uci/changes"))
include("admin_uci/changelog")
-%>
<h2 name="content"><%:Configuration%> / <%:Changes%></h2>
<% if changes then %>
<%- uci_changelog(changes) -%>
<% else %>
<p><strong><%:There are no pending changes!%></strong></p>
<% end %>
<div class="alert-message" id="cbi_apply_status" style="display:none"></div>
<div class="cbi-page-actions">
<% if redir_url then %>
<form method="get" action="<%=luci.util.pcdata(redir_url)%>">
<input class="cbi-button cbi-button-link" type="submit" value="<%:Back%>" />
</form>
<% end %>
<form method="post" action="<%=url("admin/uci/changes")%>">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="redir" value="<%=pcdata(luci.http.formvalue("redir"))%>" />
<input class="cbi-button cbi-button-save" type="submit" name="trigger_apply" value="<%:Save & Apply%>" />
</form>
<form method="post" action="<%=url("admin/uci/revert")%>">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="redir" value="<%=pcdata(luci.http.formvalue("redir"))%>" />
<input class="cbi-button cbi-button-reset" type="submit" value="<%:Revert%>" />
</form>
</div>
<%+footer%>

View file

@ -1,33 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2018 Jo-Philipp Wich <jo@mein.io>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<%-
local node, redir_url = luci.dispatcher.lookup(luci.http.formvalue("redir"))
export("redirect", redir_url or url("admin/uci/changes"))
include("admin_uci/changelog")
-%>
<h2 name="content"><%:Configuration%> / <%:Revert%></h2>
<% if changes then %>
<p><strong><%:The following changes have been reverted%>:</strong></p>
<%- uci_changelog(changes) -%>
<% else %>
<p><strong><%:There are no pending changes to revert!%></strong></p>
<% end %>
<% if redir_url then %>
<div class="cbi-page-actions">
<form class="inline" method="get" action="<%=luci.util.pcdata(redir_url)%>">
<input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" />
</form>
</div>
<% end %>
<%+footer%>

View file

@ -1,168 +0,0 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
var freqlist = <%= luci.http.write_json(self.iwinfo.freqlist) %>;
var hwmodes = <%= luci.http.write_json(self.iwinfo.hwmodelist or {}) %>;
var htmodes = <%= luci.http.write_json(self.iwinfo.htmodelist) %>;
var channels = {
'11g': [
'auto', 'auto', true
],
'11a': [
'auto', 'auto', true
]
};
for (var i = 0; i < freqlist.length; i++)
channels[(freqlist[i].mhz > 2484) ? '11a' : '11g'].push(
freqlist[i].channel,
'%d (%d MHz)'.format(freqlist[i].channel, freqlist[i].mhz),
!freqlist[i].restricted
);
var modes = [
'', 'Legacy', true,
'n', 'N', hwmodes.n,
'ac', 'AC', hwmodes.ac
];
var htmodes = {
'': [
'', '-', true
],
'n': [
'HT20', '20 MHz', htmodes.HT20,
'HT40', '40 MHz', htmodes.HT40
],
'ac': [
'VHT20', '20 MHz', htmodes.VHT20,
'VHT40', '40 MHz', htmodes.VHT40,
'VHT80', '80 MHz', htmodes.VHT80,
'VHT160', '160 MHz', htmodes.VHT160
]
};
var bands = {
'': [
'11g', '2.4 GHz', (channels['11g'].length > 3),
'11a', '5 GHz', (channels['11a'].length > 3)
],
'n': [
'11g', '2.4 GHz', (channels['11g'].length > 3),
'11a', '5 GHz', (channels['11a'].length > 3)
],
'ac': [
'11a', '5 GHz', true
]
};
function cbi_set_values(sel, vals)
{
if (sel.vals)
sel.vals.selected = sel.selectedIndex;
while (sel.options[0])
sel.remove(0);
for (var i = 0; vals && i < vals.length; i += 3)
{
if (!vals[i+2])
continue;
var opt = document.createElement('option');
opt.value = vals[i+0];
opt.text = vals[i+1];
sel.add(opt);
}
if (!isNaN(vals.selected))
sel.selectedIndex = vals.selected;
sel.parentNode.style.display = (sel.options.length <= 1) ? 'none' : '';
sel.vals = vals;
}
function cbi_toggle_wifi_mode(id)
{
cbi_toggle_wifi_htmode(id);
cbi_toggle_wifi_band(id);
}
function cbi_toggle_wifi_htmode(id)
{
var mode = document.getElementById(id + '.mode');
var bwdt = document.getElementById(id + '.htmode');
cbi_set_values(bwdt, htmodes[mode.value]);
}
function cbi_toggle_wifi_band(id)
{
var mode = document.getElementById(id + '.mode');
var band = document.getElementById(id + '.band');
cbi_set_values(band, bands[mode.value]);
cbi_toggle_wifi_channel(id);
}
function cbi_toggle_wifi_channel(id)
{
var band = document.getElementById(id + '.band');
var chan = document.getElementById(id + '.channel');
cbi_set_values(chan, channels[band.value]);
}
function cbi_init_wifi(id)
{
var mode = document.getElementById(id + '.mode');
var band = document.getElementById(id + '.band');
var chan = document.getElementById(id + '.channel');
var bwdt = document.getElementById(id + '.htmode');
cbi_set_values(mode, modes);
if (/VHT20|VHT40|VHT80|VHT160/.test(<%= luci.http.write_json(self.map:get(section, "htmode")) %>))
mode.value = 'ac';
else if (/HT20|HT40/.test(<%= luci.http.write_json(self.map:get(section, "htmode")) %>))
mode.value = 'n';
else
mode.value = '';
cbi_toggle_wifi_mode(id);
if (/a/.test(<%= luci.http.write_json(self.map:get(section, "hwmode")) %>))
band.value = '11a';
else
band.value = '11g';
cbi_toggle_wifi_band(id);
bwdt.value = <%= luci.http.write_json(self.map:get(section, "htmode")) %>;
chan.value = <%= luci.http.write_json(self.map:get(section, "channel")) %>;
}
//]]></script>
<label style="float:left; margin-right:3px">
<%:Mode%><br />
<select style="width:auto" id="<%= cbid %>.mode" name="<%= cbid %>.mode" onchange="cbi_toggle_wifi_mode('<%= cbid %>')"></select>
</label>
<label style="float:left; margin-right:3px">
<%:Band%><br />
<select style="width:auto" id="<%= cbid %>.band" name="<%= cbid %>.band" onchange="cbi_toggle_wifi_band('<%= cbid %>')"></select>
</label>
<label style="float:left; margin-right:3px">
<%:Channel%><br />
<select style="width:auto" id="<%= cbid %>.channel" name="<%= cbid %>.channel"></select>
</label>
<label style="float:left; margin-right:3px">
<%:Width%><br />
<select style="width:auto" id="<%= cbid %>.htmode" name="<%= cbid %>.htmode"></select>
</label>
<br style="clear:left" />
<script type="text/javascript">cbi_init_wifi('<%= cbid %>');</script>
<%+cbi/valuefooter%>

View file

@ -1,118 +0,0 @@
#!/bin/sh /etc/rc.common
START=4
USE_PROCD=1
_setup_macaddr() {
uci -q get "network.$1_dev.macaddr" >/dev/null && return
uci -q set "network.$1_dev.macaddr=$2"
}
_save_macaddr() {
local _ifname
local _macaddr
uci -q get "network.$1_dev.ifname" >/dev/null && {
_ifname=$(uci -q get "network.$1.ifname")
if [ -n "$(uci -q get network.$1.macaddr)" ] && [ "$(uci -q get network.$1.macaddr)" != "$(uci -q get network.$1_dev.macaddr)" ]; then
uci -q set network.$1_dev.macaddr="$(uci -q get network.$1.macaddr)"
else
_macaddr=$(ip link show dev $_ifname 2>/dev/null | grep link | awk '{print $2}')
[ -n "$_macaddr" ] && {
uci -q set network.$1_dev.macaddr=$_macaddr
uci -q set network.$1.macaddr=$_macaddr
}
fi
}
[ -z "$(uci -q get network.$1.macaddr)" ] && {
_ifname=$(uci -q get "network.$1.ifname")
[ -n "$_ifname" ] && {
_macaddr=$(ip link show dev $_ifname 2>/dev/null | grep link | awk '{print $2}')
[ -n "$_macaddr" ] && {
uci -q set network.$1.macaddr=$_macaddr
}
}
}
}
# Configuration by interface
_setup_interface() {
local _ifname
config_get _ifname "$1" ifname
[ -z "$_ifname" ] && config_get _ifname "$1" ifname
# do not create macvlan for vlan
#case "$_ifname" in
# eth*.*) return ;;
#esac
[ "$(echo $1 | grep _dev)" != "" ] && {
local _intfdev=$(sed 's/_dev//' $1)
uci -q get "network.$_intfdev.ifname" >/dev/null || {
uci -q batch <<-EOF
delete network.$1
commit network
EOF
}
return
}
local _type
config_get _type "$1" type
uci -q get "network.$1_dev.ifname" >/dev/null && {
uci -q set network.$1_dev.mtu=$(uci -q get network.$1.mtu)
[ -z "$(uci -q get network.$1.masterintf)" ] && uci -q set network.$1.masterintf=$(uci -q get network.$1_dev.ifname)
[ -n "$(uci -q get network.$1.masterintf)" ] && uci -q set network.$1_dev.ifname=$(uci -q get network.$1.masterintf)
[ -z "$(uci -q get network.$1.macaddr)" ] && uci -q set network.$1_dev.macaddr=$(uci -q get network.$1.macaddr)
[ "$_type" = "macvlan" ] || {
uci -q batch <<-EOF
delete network.$1_dev
EOF
}
[ "$_type" = "macvlan" ] && {
local interface
config_get _interface "$1" interface
[ -n "$_interface" ] && {
uci -q batch <<-EOF
delete network.$1.interface
set network.$1_dev.ifname=$_interface
EOF
}
}
uci -q commit network
return 0
}
[ "$_type" = "macvlan" ] || return 0
uci -q batch <<-EOF
set network.$1_dev=device
set network.$1_dev.name=$1
set network.$1_dev.type=macvlan
set network.$1_dev.ifname=$_ifname
set network.$1.ifname=$1
set network.$1.masterintf=$_ifname
set network.$1.type=macvlan
set network.$1.defaultroute=0
EOF
_macaddr=$(uci -q get "network.$1.macaddr")
_setup_macaddr "$1" "${_macaddr:-auto$(date +%s)}"
uci -q set network.$1_dev.mtu=$(uci -q get network.$1.mtu)
uci -q commit network
}
start_service() {
. /lib/functions.sh
config_load network
config_foreach _setup_interface interface
config_foreach _save_macaddr interface
uci -q commit network
}
reload_service() {
start
}
service_triggers() {
procd_add_reload_trigger network
}

View file

@ -1,22 +0,0 @@
#!/bin/sh
if [ "$(uci -q get luci.diag)" != "internal" ]; then
host=""
if [ -s /etc/os-release ]; then
. /etc/os-release
host="${HOME_URL:-${BUG_URL:-$LEDE_DEVICE_MANUFACTURER_URL}}"
host="${host#*://}"
host="${host%%/*}"
fi
uci -q batch <<-EOF >/dev/null
set luci.diag=internal
set luci.diag.dns='openmptcprouter.com'
set luci.diag.ping='openmptcprouter.com'
set luci.diag.route='openmptcprouter.com'
commit luci
EOF
fi
exit 0

View file

@ -1,14 +0,0 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@macvlan[-1]
add ucitrack macvlan
set ucitrack.@macvlan[-1].init=macvlan
commit ucitrack
EOF
if [ "$(uci -q get ucitrack.@network[-1].affects | grep macvlan)" = "" ]; then
uci -q batch <<-EOF >/dev/null
add_list ucitrack.@network[-1].affects=macvlan
commit ucitrack
EOF
fi
exit 0

View file

@ -1,14 +0,0 @@
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(FPIC) -c -o $@ $<
clean:
rm -f luci-bwc *.o
luci-bwc: luci-bwc.o
$(CC) $(LDFLAGS) -o $@ $^ -ldl
compile: luci-bwc
install: compile
mkdir -p $(DESTDIR)/usr/bin
cp luci-bwc $(DESTDIR)/usr/bin/luci-bwc

View file

@ -1,778 +0,0 @@
/*
* luci-bwc - Very simple bandwidth collector cache for LuCI realtime graphs
*
* Copyright (C) 2010 Jo-Philipp Wich <jow@openwrt.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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <dlfcn.h>
#include <iwinfo.h>
#define STEP_COUNT 60
#define STEP_TIME 1
#define TIMEOUT 10
#define PID_PATH "/var/run/luci-bwc.pid"
#define DB_PATH "/var/lib/luci-bwc"
#define DB_IF_FILE DB_PATH "/if/%s"
#define DB_RD_FILE DB_PATH "/radio/%s"
#define DB_CN_FILE DB_PATH "/connections"
#define DB_LD_FILE DB_PATH "/load"
#define IF_SCAN_PATTERN \
" %[^ :]:%u %u" \
" %*d %*d %*d %*d %*d %*d" \
" %u %u"
#define LD_SCAN_PATTERN \
"%f %f %f"
struct file_map {
int fd;
int size;
char *mmap;
};
struct traffic_entry {
uint32_t time;
uint32_t rxb;
uint32_t rxp;
uint32_t txb;
uint32_t txp;
};
struct conn_entry {
uint32_t time;
uint32_t udp;
uint32_t tcp;
uint32_t other;
};
struct load_entry {
uint32_t time;
uint16_t load1;
uint16_t load5;
uint16_t load15;
};
struct radio_entry {
uint32_t time;
uint16_t rate;
uint8_t rssi;
uint8_t noise;
};
static int readpid(void)
{
int fd;
int pid = -1;
char buf[9] = { 0 };
if ((fd = open(PID_PATH, O_RDONLY)) > -1)
{
if (read(fd, buf, sizeof(buf)))
{
buf[8] = 0;
pid = atoi(buf);
}
close(fd);
}
return pid;
}
static int writepid(void)
{
int fd;
int wlen;
char buf[9] = { 0 };
if ((fd = open(PID_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0600)) > -1)
{
wlen = snprintf(buf, sizeof(buf), "%i", getpid());
write(fd, buf, wlen);
close(fd);
return 0;
}
return -1;
}
static int timeout = TIMEOUT;
static int countdown = -1;
static void reset_countdown(int sig)
{
countdown = timeout;
}
static char *progname;
static int prognamelen;
static struct iwinfo_ops *backend = NULL;
static int init_directory(char *path)
{
char *p = path;
for (p = &path[1]; *p; p++)
{
if (*p == '/')
{
*p = 0;
if (mkdir(path, 0700) && (errno != EEXIST))
return -1;
*p = '/';
}
}
return 0;
}
static int init_file(char *path, int esize)
{
int i, file;
char buf[sizeof(struct traffic_entry)] = { 0 };
if (init_directory(path))
return -1;
if ((file = open(path, O_WRONLY | O_CREAT, 0600)) >= 0)
{
for (i = 0; i < STEP_COUNT; i++)
{
if (write(file, buf, esize) < 0)
break;
}
close(file);
return 0;
}
return -1;
}
static inline uint32_t timeof(void *entry)
{
return ntohl(((struct traffic_entry *)entry)->time);
}
static int update_file(const char *path, void *entry, int esize)
{
int rv = -1;
int file;
char *map;
if ((file = open(path, O_RDWR)) >= 0)
{
map = mmap(NULL, esize * STEP_COUNT, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_LOCKED, file, 0);
if ((map != NULL) && (map != MAP_FAILED))
{
if (timeof(entry) > timeof(map + esize * (STEP_COUNT-1)))
{
memmove(map, map + esize, esize * (STEP_COUNT-1));
memcpy(map + esize * (STEP_COUNT-1), entry, esize);
}
munmap(map, esize * STEP_COUNT);
rv = 0;
}
close(file);
}
return rv;
}
static int mmap_file(const char *path, int esize, struct file_map *m)
{
m->fd = -1;
m->size = -1;
m->mmap = NULL;
if ((m->fd = open(path, O_RDONLY)) >= 0)
{
m->size = STEP_COUNT * esize;
m->mmap = mmap(NULL, m->size, PROT_READ,
MAP_SHARED | MAP_LOCKED, m->fd, 0);
if ((m->mmap != NULL) && (m->mmap != MAP_FAILED))
return 0;
}
return -1;
}
static void umap_file(struct file_map *m)
{
if ((m->mmap != NULL) && (m->mmap != MAP_FAILED))
munmap(m->mmap, m->size);
if (m->fd > -1)
close(m->fd);
}
static void * iw_open(void)
{
return dlopen("/usr/lib/libiwinfo.so", RTLD_LAZY);
}
static int iw_update(
void *iw, const char *ifname, uint16_t *rate, uint8_t *rssi, uint8_t *noise
) {
struct iwinfo_ops *(*probe)(const char *);
int val;
if (!backend)
{
probe = dlsym(iw, "iwinfo_backend");
if (!probe)
return 0;
backend = probe(ifname);
if (!backend)
return 0;
}
*rate = (backend->bitrate && !backend->bitrate(ifname, &val)) ? val : 0;
*rssi = (backend->signal && !backend->signal(ifname, &val)) ? val : 0;
*noise = (backend->noise && !backend->noise(ifname, &val)) ? val : 0;
return 1;
}
static void iw_close(void *iw)
{
void (*finish)(void);
finish = dlsym(iw, "iwinfo_finish");
if (finish)
finish();
dlclose(iw);
}
static int update_ifstat(
const char *ifname, uint32_t rxb, uint32_t rxp, uint32_t txb, uint32_t txp
) {
char path[1024];
struct stat s;
struct traffic_entry e;
snprintf(path, sizeof(path), DB_IF_FILE, ifname);
if (stat(path, &s))
{
if (init_file(path, sizeof(struct traffic_entry)))
{
fprintf(stderr, "Failed to init %s: %s\n",
path, strerror(errno));
return -1;
}
}
e.time = htonl(time(NULL));
e.rxb = htonl(rxb);
e.rxp = htonl(rxp);
e.txb = htonl(txb);
e.txp = htonl(txp);
return update_file(path, &e, sizeof(struct traffic_entry));
}
static int update_radiostat(
const char *ifname, uint16_t rate, uint8_t rssi, uint8_t noise
) {
char path[1024];
struct stat s;
struct radio_entry e;
snprintf(path, sizeof(path), DB_RD_FILE, ifname);
if (stat(path, &s))
{
if (init_file(path, sizeof(struct radio_entry)))
{
fprintf(stderr, "Failed to init %s: %s\n",
path, strerror(errno));
return -1;
}
}
e.time = htonl(time(NULL));
e.rate = htons(rate);
e.rssi = rssi;
e.noise = noise;
return update_file(path, &e, sizeof(struct radio_entry));
}
static int update_cnstat(uint32_t udp, uint32_t tcp, uint32_t other)
{
char path[1024];
struct stat s;
struct conn_entry e;
snprintf(path, sizeof(path), DB_CN_FILE);
if (stat(path, &s))
{
if (init_file(path, sizeof(struct conn_entry)))
{
fprintf(stderr, "Failed to init %s: %s\n",
path, strerror(errno));
return -1;
}
}
e.time = htonl(time(NULL));
e.udp = htonl(udp);
e.tcp = htonl(tcp);
e.other = htonl(other);
return update_file(path, &e, sizeof(struct conn_entry));
}
static int update_ldstat(uint16_t load1, uint16_t load5, uint16_t load15)
{
char path[1024];
struct stat s;
struct load_entry e;
snprintf(path, sizeof(path), DB_LD_FILE);
if (stat(path, &s))
{
if (init_file(path, sizeof(struct load_entry)))
{
fprintf(stderr, "Failed to init %s: %s\n",
path, strerror(errno));
return -1;
}
}
e.time = htonl(time(NULL));
e.load1 = htons(load1);
e.load5 = htons(load5);
e.load15 = htons(load15);
return update_file(path, &e, sizeof(struct load_entry));
}
static int run_daemon(void)
{
FILE *info;
uint32_t rxb, txb, rxp, txp;
uint32_t udp, tcp, other;
uint16_t rate;
uint8_t rssi, noise;
float lf1, lf5, lf15;
char line[1024];
char ifname[16];
int i;
void *iw;
struct sigaction sa;
struct stat s;
const char *ipc = stat("/proc/net/nf_conntrack", &s)
? "/proc/net/ip_conntrack" : "/proc/net/nf_conntrack";
switch (fork())
{
case -1:
perror("fork()");
return -1;
case 0:
if (chdir("/") < 0)
{
perror("chdir()");
exit(1);
}
close(0);
close(1);
close(2);
break;
default:
return 0;
}
/* setup USR1 signal handler to reset timer */
sa.sa_handler = reset_countdown;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
/* write pid */
if (writepid())
{
fprintf(stderr, "Failed to write pid file: %s\n", strerror(errno));
return 1;
}
/* initialize iwinfo */
iw = iw_open();
/* go */
for (reset_countdown(0); countdown >= 0; countdown--)
{
/* alter progname for ps, top */
memset(progname, 0, prognamelen);
snprintf(progname, prognamelen, "luci-bwc %d", countdown);
if ((info = fopen("/proc/net/dev", "r")) != NULL)
{
while (fgets(line, sizeof(line), info))
{
if (strchr(line, '|'))
continue;
if (sscanf(line, IF_SCAN_PATTERN, ifname, &rxb, &rxp, &txb, &txp))
{
if (strncmp(ifname, "lo", sizeof(ifname)))
update_ifstat(ifname, rxb, rxp, txb, txp);
}
}
fclose(info);
}
if (iw)
{
for (i = 0; i < 5; i++)
{
#define iw_checkif(pattern) \
do { \
snprintf(ifname, sizeof(ifname), pattern, i); \
if (iw_update(iw, ifname, &rate, &rssi, &noise)) \
{ \
update_radiostat(ifname, rate, rssi, noise); \
continue; \
} \
} while(0)
iw_checkif("wlan%d");
iw_checkif("ath%d");
iw_checkif("wl%d");
}
}
if ((info = fopen(ipc, "r")) != NULL)
{
udp = 0;
tcp = 0;
other = 0;
while (fgets(line, sizeof(line), info))
{
if (strstr(line, "TIME_WAIT"))
continue;
if ((strstr(line, "src=127.0.0.1 ") && strstr(line, "dst=127.0.0.1 "))
|| (strstr(line, "src=::1 ") && strstr(line, "dst=::1 ")))
continue;
if (sscanf(line, "%*s %*d %s", ifname) || sscanf(line, "%s %*d", ifname))
{
if (!strcmp(ifname, "tcp"))
tcp++;
else if (!strcmp(ifname, "udp"))
udp++;
else
other++;
}
}
update_cnstat(udp, tcp, other);
fclose(info);
}
if ((info = fopen("/proc/loadavg", "r")) != NULL)
{
if (fscanf(info, LD_SCAN_PATTERN, &lf1, &lf5, &lf15))
{
update_ldstat((uint16_t)(lf1 * 100),
(uint16_t)(lf5 * 100),
(uint16_t)(lf15 * 100));
}
fclose(info);
}
sleep(STEP_TIME);
}
unlink(PID_PATH);
if (iw)
iw_close(iw);
return 0;
}
static void check_daemon(void)
{
int pid;
if ((pid = readpid()) < 0 || kill(pid, 0) < 0)
{
/* daemon ping failed, try to start it up */
if (run_daemon())
{
fprintf(stderr,
"Failed to ping daemon and unable to start it up: %s\n",
strerror(errno));
exit(1);
}
}
else if (kill(pid, SIGUSR1))
{
fprintf(stderr, "Failed to send signal: %s\n", strerror(errno));
exit(2);
}
}
static int run_dump_ifname(const char *ifname)
{
int i;
char path[1024];
struct file_map m;
struct traffic_entry *e;
check_daemon();
snprintf(path, sizeof(path), DB_IF_FILE, ifname);
if (mmap_file(path, sizeof(struct traffic_entry), &m))
{
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
for (i = 0; i < m.size; i += sizeof(struct traffic_entry))
{
e = (struct traffic_entry *) &m.mmap[i];
if (!e->time)
continue;
printf("[ %u, %u, %" PRIu32
", %u, %u ]%s\n",
ntohl(e->time),
ntohl(e->rxb), ntohl(e->rxp),
ntohl(e->txb), ntohl(e->txp),
((i + sizeof(struct traffic_entry)) < m.size) ? "," : "");
}
umap_file(&m);
return 0;
}
static int run_dump_radio(const char *ifname)
{
int i;
char path[1024];
struct file_map m;
struct radio_entry *e;
check_daemon();
snprintf(path, sizeof(path), DB_RD_FILE, ifname);
if (mmap_file(path, sizeof(struct radio_entry), &m))
{
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
for (i = 0; i < m.size; i += sizeof(struct radio_entry))
{
e = (struct radio_entry *) &m.mmap[i];
if (!e->time)
continue;
printf("[ %u, %d, %d, %d ]%s\n",
ntohl(e->time),
e->rate, e->rssi, e->noise,
((i + sizeof(struct radio_entry)) < m.size) ? "," : "");
}
umap_file(&m);
return 0;
}
static int run_dump_conns(void)
{
int i;
char path[1024];
struct file_map m;
struct conn_entry *e;
check_daemon();
snprintf(path, sizeof(path), DB_CN_FILE);
if (mmap_file(path, sizeof(struct conn_entry), &m))
{
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
for (i = 0; i < m.size; i += sizeof(struct conn_entry))
{
e = (struct conn_entry *) &m.mmap[i];
if (!e->time)
continue;
printf("[ %u, %u, %u, %u ]%s\n",
ntohl(e->time), ntohl(e->udp),
ntohl(e->tcp), ntohl(e->other),
((i + sizeof(struct conn_entry)) < m.size) ? "," : "");
}
umap_file(&m);
return 0;
}
static int run_dump_load(void)
{
int i;
char path[1024];
struct file_map m;
struct load_entry *e;
check_daemon();
snprintf(path, sizeof(path), DB_LD_FILE);
if (mmap_file(path, sizeof(struct load_entry), &m))
{
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
for (i = 0; i < m.size; i += sizeof(struct load_entry))
{
e = (struct load_entry *) &m.mmap[i];
if (!e->time)
continue;
printf("[ %u, %u, %u, %u ]%s\n",
ntohl(e->time),
ntohs(e->load1), ntohs(e->load5), ntohs(e->load15),
((i + sizeof(struct load_entry)) < m.size) ? "," : "");
}
umap_file(&m);
return 0;
}
int main(int argc, char *argv[])
{
int opt;
progname = argv[0];
prognamelen = -1;
for (opt = 0; opt < argc; opt++)
prognamelen += 1 + strlen(argv[opt]);
while ((opt = getopt(argc, argv, "t:i:r:cl")) > -1)
{
switch (opt)
{
case 't':
timeout = atoi(optarg);
break;
case 'i':
if (optarg)
return run_dump_ifname(optarg);
break;
case 'r':
if (optarg)
return run_dump_radio(optarg);
break;
case 'c':
return run_dump_conns();
case 'l':
return run_dump_load();
default:
break;
}
}
fprintf(stderr,
"Usage:\n"
" %s [-t timeout] -i ifname\n"
" %s [-t timeout] -r radiodev\n"
" %s [-t timeout] -c\n"
" %s [-t timeout] -l\n",
argv[0], argv[0], argv[0], argv[0]
);
return 1;
}