diff --git a/modules/luci-mod-admin-full/Makefile b/modules/luci-mod-admin-full/Makefile
index 36ddf13f16..b376b35e55 100644
--- a/modules/luci-mod-admin-full/Makefile
+++ b/modules/luci-mod-admin-full/Makefile
@@ -7,9 +7,8 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI Administration - full-featured for full control
-LUCI_DEPENDS:=+luci-base
+LUCI_DEPENDS:=+luci-base +luci-mod-status +luci-mod-system +luci-mod-network
-PKG_BUILD_DEPENDS:=iwinfo
PKG_LICENSE:=Apache-2.0
include ../../luci.mk
diff --git a/modules/luci-mod-admin-full/htdocs/luci-static/resources/bandwidth.svg b/modules/luci-mod-admin-full/htdocs/luci-static/resources/bandwidth.svg
deleted file mode 100644
index 5a121b85c6..0000000000
--- a/modules/luci-mod-admin-full/htdocs/luci-static/resources/bandwidth.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/modules/luci-mod-admin-full/htdocs/luci-static/resources/connections.svg b/modules/luci-mod-admin-full/htdocs/luci-static/resources/connections.svg
deleted file mode 100644
index 5794e79426..0000000000
--- a/modules/luci-mod-admin-full/htdocs/luci-static/resources/connections.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
diff --git a/modules/luci-mod-admin-full/htdocs/luci-static/resources/load.svg b/modules/luci-mod-admin-full/htdocs/luci-static/resources/load.svg
deleted file mode 100644
index 716d37617f..0000000000
--- a/modules/luci-mod-admin-full/htdocs/luci-static/resources/load.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
diff --git a/modules/luci-mod-admin-full/htdocs/luci-static/resources/wifirate.svg b/modules/luci-mod-admin-full/htdocs/luci-static/resources/wifirate.svg
deleted file mode 100644
index e75ea614c9..0000000000
--- a/modules/luci-mod-admin-full/htdocs/luci-static/resources/wifirate.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
diff --git a/modules/luci-mod-admin-full/htdocs/luci-static/resources/wireless.svg b/modules/luci-mod-admin-full/htdocs/luci-static/resources/wireless.svg
deleted file mode 100644
index 00cc2a12f1..0000000000
--- a/modules/luci-mod-admin-full/htdocs/luci-static/resources/wireless.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
deleted file mode 100644
index c4e1c3aa16..0000000000
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
+++ /dev/null
@@ -1,442 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2011-2018 Jo-Philipp Wich
--- 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
-
--- 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
--- 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 % luci.util.shellquote(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
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua
deleted file mode 100644
index 4f04cce545..0000000000
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua
+++ /dev/null
@@ -1,153 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2011 Jo-Philipp Wich
--- Licensed to the public under the Apache License 2.0.
-
-module("luci.controller.admin.status", package.seeall)
-
-function index()
- 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
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua
deleted file mode 100644
index 4e83769ee0..0000000000
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua
+++ /dev/null
@@ -1,469 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2008-2011 Jo-Philipp Wich
--- 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", "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"), _("LED 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", "backupmtdblock"}, post("action_backupmtdblock"))
- 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
- local force = http.formvalue("force")
- if image_supported(image_tmp) or force 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")),
- force = (not not http.formvalue("force"))
- })
- 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"
- local force = (http.formvalue("force") == "1") and "-F" or ""
- luci.template.render("admin_system/applyreboot", {
- title = luci.i18n.translate("Flashing..."),
- msg = luci.i18n.translate("The system is flashing now. DO NOT POWER OFF THE DEVICE! 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 (#force > 0) and "192.168.1.1" or nil
- })
- fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %s %q" %{ keep, force, 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_backupmtdblock()
- local http = require "luci.http"
- local mv = http.formvalue("mtdblockname")
- local m, s, n = mv:match('^([^%s]+)/([^%s]+)/([^%s]+)')
-
- local reader = ltn12_popen("dd if=/dev/mtd%s conv=fsync,notrunc 2>/dev/null" % n)
-
- luci.http.header(
- 'Content-Disposition', 'attachment; filename="backup-%s-%s-%s.bin"' %{
- luci.sys.hostname(), m,
- os.date("%Y-%m-%d")
- })
-
- luci.http.prepare_content("application/octet-stream")
- 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
deleted file mode 100644
index ae8a95f9ce..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
+++ /dev/null
@@ -1,346 +0,0 @@
--- Copyright 2008 Steven Barth
--- 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 DHCP-Server and DNS-" ..
- "Forwarder for NAT " ..
- "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 DNS-Requests without " ..
- "DNS-Name"))
-
-s:taboption("general", Flag, "authoritative",
- translate("Authoritative"),
- translate("This is the only DHCP" ..
- "abbr> in the local network"))
-
-
-s:taboption("files", Flag, "readethers",
- translate("Use /etc/ethers"),
- translate("Read /etc/ethers to configure the DHCP-Server"))
-
-s:taboption("files", Value, "leasefile",
- translate("Leasefile"),
- translate("file where given 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 DNS file"))
-
-rf:depends("noresolv", "")
-rf.optional = true
-
-
-s:taboption("files", Flag, "nohosts",
- translate("Ignore /etc/hosts")).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 DNS servers."))
-
-s:taboption("advanced", Flag, "strictorder",
- translate("Strict order"),
- translate("DNS 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 DNS 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 DNS " ..
- "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("DNS 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("DNS 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("Max. DHCP 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("Max. EDNS0 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("Max. 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.") .. " " ..
- translate("Use the Add Button to add a new lease entry. The MAC-Address " ..
- "identifies the host, the IPv4-Address specifies the fixed address to " ..
- "use, and the Hostname is assigned as a symbolic name to the requesting host. " ..
- "The optional Lease time 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("MAC-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("IPv4-Address"))
-ip.datatype = "or(ip4addr,'ignore')"
-
-time = s:option(Value, "leasetime", translate("Lease time"))
-time.rmempty = true
-
-duid = s:option(Value, "duid", translate("DUID"))
-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("IPv6-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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua
deleted file mode 100644
index 46945af58b..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua
+++ /dev/null
@@ -1,31 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2010-2015 Jo-Philipp Wich
--- 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua
deleted file mode 100644
index ca66e9f365..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua
+++ /dev/null
@@ -1,101 +0,0 @@
--- Copyright 2009-2010 Jo-Philipp Wich
--- 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: A-Z, a-z, " ..
- "0-9 and _"
- ))
-
-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"))
-
-
-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
-
-
-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_floating() then
- sifname:depends({ _bridge = "", _netproto = p:proto()})
- mifname:depends({ _bridge = "1", _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)
- 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 })
- if net then
- local ifn
- for ifn in utl.imatch(
- br 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua
deleted file mode 100644
index 8be354b448..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua
+++ /dev/null
@@ -1,563 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2008-2011 Jo-Philipp Wich
--- 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 VLAN notation INTERFACE.VLANNR (e.g.: eth0.1)."))
-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 = s[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
-
-
-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
-
-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")
-
- stp = s:taboption("physical", Flag, "stp", translate("Enable STP"),
- 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 IGMP snooping"),
- translate("Enables IGMP snooping on this bridge"))
- igmp:depends("type", "bridge")
- igmp.rmempty = true
-end
-
-
-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 unspecified to remove the interface from the associated zone or fill out the create 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 DHCP 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 (2m)."))
- ltime.rmempty = true
- ltime.default = "12h"
-
- local dd = s:taboption("advanced", Flag, "dynamicdhcp",
- translate("Dynamic DHCP"),
- 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("IPv4-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 \"6,192.168.2.1," ..
- "192.168.2.2\" 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua
deleted file mode 100644
index 799386d29c..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua
+++ /dev/null
@@ -1,265 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2008 Jo-Philipp Wich
--- 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"
-
-m = Map("network", translate("Interfaces"))
-m:chain("wireless")
-m:chain("firewall")
-m:chain("dhcp")
-m.pageaction = false
-
-
-local tpl_networks = tpl.Template(nil, [[
-
-
- <%
- 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()
- %>
-
-
-
-
- <%=net[1]:upper()%>
-
-
-
- ?
-
-
-
-
- <%:Collecting data...%>
-
-
-
- />
-
- <% if disabled then %>
-
- />
- <% else %>
-
- />
- <% end %>
-
- '" title="<%:Edit this interface%>" value="<%:Edit%>" id="<%=net[1]%>-ifc-edit"<%=ifattr(dynamic, "disabled", "disabled")%> />
-
-
- />
-
-
-
- <% end %>
-
-
-
- '" />
-
-]])
-
-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"
-if network:has_ipv6() then
- local s = m:section(NamedSection, "globals", "globals", translate("Global network options"))
- local o = s:option(Value, "ula_prefix", translate("IPv6 ULA-Prefix"))
- o.datatype = "ip6addr"
- o.rmempty = true
- m.pageaction = true
-end
-
-
-return m
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/proto_ahcp.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/proto_ahcp.lua
deleted file mode 100644
index 0818199a93..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/proto_ahcp.lua
+++ /dev/null
@@ -1,67 +0,0 @@
--- Copyright 2011 Jo-Philipp Wich
--- 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")
-
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua
deleted file mode 100644
index 1970f36a28..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua
+++ /dev/null
@@ -1,102 +0,0 @@
--- Copyright 2008 Steven Barth
--- 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-IP or Network"))
-t.datatype = "ip4addr"
-t.rmempty = false
-
-n = s:option(Value, "netmask", translate("IPv4-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("IPv4-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
-
-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("IPv6-Address or Network (CIDR)"))
- t.datatype = "ip6addr"
- t.rmempty = false
-
- g = s:option(Value, "gateway", translate("IPv6-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
-
- 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua
deleted file mode 100644
index d79b3c4704..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua
+++ /dev/null
@@ -1,364 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2010-2011 Jo-Philipp Wich
--- 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 VLANs in which computers can communicate directly with each other. VLANs 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 = section.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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
deleted file mode 100644
index 743efaa1e8..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
+++ /dev/null
@@ -1,1101 +0,0 @@
--- Copyright 2008 Steven Barth
--- Licensed to the public under the Apache License 2.0.
-
-local wa = require "luci.tools.webadmin"
-local nw = require "luci.model.network"
-local ut = require "luci.util"
-local nt = require "luci.sys".net
-local fs = require "nixio.fs"
-
-local acct_port, acct_secret, acct_server, anonymous_identity, ant1, ant2,
- auth, auth_port, auth_secret, auth_server, bssid, cacert, cacert2,
- cc, ch, cipher, clientcert, clientcert2, ea, eaptype, en, encr,
- ft_protocol, ft_psk_generate_local, hidden, htmode, identity,
- ieee80211r, ieee80211w, ifname, isolate, key_retries,
- legacyrates, max_timeout, meshfwd, meshid, ml, mobility_domain, mode,
- mp, nasid, network, password, pmk_r1_push, privkey, privkey2, privkeypwd,
- privkeypwd2, r0_key_lifetime, r0kh, r1_key_holder, r1kh,
- reassociation_deadline, retry_timeout, ssid, st, tp, wepkey, wepslot,
- wmm, wpakey, wps, disassoc_low_ack, short_preamble, beacon_int, dtim_period
-
-arg[1] = arg[1] or ""
-
-m = Map("wireless", "",
- translate("The Device Configuration section covers physical settings of the radio " ..
- "hardware such as channel, transmit power or antenna selection which are shared among all " ..
- "defined wireless networks (if the radio hardware is multi-SSID capable). Per network settings " ..
- "like encryption or operation mode are grouped in the Interface Configuration."))
-
-m:chain("network")
-m:chain("firewall")
-m.redirect = luci.dispatcher.build_url("admin/network/wireless")
-
-nw.init(m.uci)
-
-local wnet = nw:get_wifinet(arg[1])
-local wdev = wnet and wnet:get_device()
-
--- redirect to overview page if network does not exist anymore (e.g. after a revert)
-if not wnet or not wdev then
- luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
- return
-end
-
-local function txpower_list(iw)
- local list = iw.txpwrlist or { }
- local off = tonumber(iw.txpower_offset) or 0
- local new = { }
- local prev = -1
- local _, val
- for _, val in ipairs(list) do
- local dbm = val.dbm + off
- local mw = math.floor(10 ^ (dbm / 10))
- if mw ~= prev then
- prev = mw
- new[#new+1] = {
- display_dbm = dbm,
- display_mw = mw,
- driver_dbm = val.dbm,
- driver_mw = val.mw
- }
- end
- end
- return new
-end
-
-local function txpower_current(pwr, list)
- pwr = tonumber(pwr)
- if pwr ~= nil then
- local _, item
- for _, item in ipairs(list) do
- if item.driver_dbm >= pwr then
- return item.driver_dbm
- end
- end
- end
- return pwr or ""
-end
-
-local iw = luci.sys.wifi.getiwinfo(arg[1])
-local hw_modes = iw.hwmodelist or { }
-local tx_power_list = txpower_list(iw)
-local tx_power_cur = txpower_current(wdev:get("txpower"), tx_power_list)
-
--- wireless toggle was requested, commit and reload page
-function m.parse(map)
- local new_cc = m:formvalue("cbid.wireless.%s.country" % wdev:name())
- local old_cc = m:get(wdev:name(), "country")
-
- if m:formvalue("cbid.wireless.%s.__toggle" % wdev:name()) then
- if wdev:get("disabled") == "1" or wnet:get("disabled") == "1" then
- wnet:set("disabled", nil)
- else
- wnet:set("disabled", "1")
- end
- wdev:set("disabled", nil)
- m.apply_needed = true
- m.redirect = nil
- end
-
- Map.parse(map)
-
- if m:get(wdev:name(), "type") == "mac80211" and new_cc and new_cc ~= old_cc then
- luci.sys.call("iw reg set %s" % ut.shellquote(new_cc))
-
- local old_ch = tonumber(m:formvalue("cbid.wireless.%s._mode_freq.channel" % wdev:name()) or "")
- if old_ch then
- local _, c, new_ch
- for _, c in ipairs(iw.freqlist) do
- if c.channel > old_ch or (old_ch <= 14 and c.channel > 14) then
- break
- end
- new_ch = c.channel
- end
- if new_ch ~= old_ch then
- wdev:set("channel", new_ch)
- m.message = translatef("Channel %d is not available in the %s regulatory domain and has been auto-adjusted to %d.",
- old_ch, new_cc, new_ch)
- end
- end
- end
-
- if wdev:get("disabled") == "1" or wnet:get("disabled") == "1" then
- en.title = translate("Wireless network is disabled")
- en.inputtitle = translate("Enable")
- en.inputstyle = "apply"
- else
- en.title = translate("Wireless network is enabled")
- en.inputtitle = translate("Disable")
- en.inputstyle = "reset"
- end
-end
-
-m.title = luci.util.pcdata(wnet:get_i18n())
-
-s = m:section(NamedSection, wdev:name(), "wifi-device", translate("Device Configuration"))
-s.addremove = false
-
-s:tab("general", translate("General Setup"))
-s:tab("macfilter", translate("MAC-Filter"))
-s:tab("advanced", translate("Advanced Settings"))
-
-st = s:taboption("general", DummyValue, "__status", translate("Status"))
-st.template = "admin_network/wifi_status"
-st.ifname = arg[1]
-
-en = s:taboption("general", Button, "__toggle")
-
-local hwtype = wdev:get("type")
-
--- NanoFoo
-local nsantenna = wdev:get("antenna")
-
--- Check whether there are client interfaces on the same radio,
--- if yes, lock the channel choice as these stations will dicatate the freq
-local found_sta = nil
-local _, net
-if wnet:mode() ~= "sta" then
- for _, net in ipairs(wdev:get_wifinets()) do
- if net:mode() == "sta" and net:get("disabled") ~= "1" then
- if not found_sta then
- found_sta = {}
- found_sta.channel = net:channel()
- found_sta.names = {}
- end
- found_sta.names[#found_sta.names+1] = net:shortname()
- end
- end
-end
-
-if found_sta then
- ch = s:taboption("general", DummyValue, "choice", translate("Channel"))
- ch.value = translatef("Locked to channel %s used by: %s",
- found_sta.channel or "(auto)", table.concat(found_sta.names, ", "))
-else
- ch = s:taboption("general", Value, "_mode_freq", ' '..translate("Operating frequency"))
- ch.iwinfo = iw
- ch.template = "cbi/wireless_modefreq"
-
- function ch.cfgvalue(self, section)
- return {
- m:get(section, "hwmode") or "",
- m:get(section, "channel") or "auto",
- m:get(section, "htmode") or ""
- }
- end
-
- function ch.formvalue(self, section)
- return {
- m:formvalue(self:cbid(section) .. ".band") or (hw_modes.g and "11g" or "11a"),
- m:formvalue(self:cbid(section) .. ".channel") or "auto",
- m:formvalue(self:cbid(section) .. ".htmode") or ""
- }
- end
-
- function ch.write(self, section, value)
- m:set(section, "hwmode", value[1])
- m:set(section, "channel", value[2])
- m:set(section, "htmode", value[3])
- end
-end
-
-------------------- MAC80211 Device ------------------
-
-if hwtype == "mac80211" then
- if #tx_power_list > 0 then
- tp = s:taboption("general", ListValue,
- "txpower", translate("Transmit Power"), "dBm")
- tp.rmempty = true
- tp.default = tx_power_cur
- function tp.cfgvalue(...)
- return txpower_current(Value.cfgvalue(...), tx_power_list)
- end
-
- tp:value("", translate("auto"))
- for _, p in ipairs(tx_power_list) do
- tp:value(p.driver_dbm, "%i dBm (%i mW)"
- %{ p.display_dbm, p.display_mw })
- end
- end
-
- local cl = iw and iw.countrylist
- if cl and #cl > 0 then
- cc = s:taboption("advanced", ListValue, "country", translate("Country Code"), translate("Use ISO/IEC 3166 alpha2 country codes."))
- cc.default = tostring(iw and iw.country or "00")
- for _, c in ipairs(cl) do
- cc:value(c.alpha2, "%s - %s" %{ c.alpha2, c.name })
- end
- else
- s:taboption("advanced", Value, "country", translate("Country Code"), translate("Use ISO/IEC 3166 alpha2 country codes."))
- end
-
- legacyrates = s:taboption("advanced", Flag, "legacy_rates", translate("Allow legacy 802.11b rates"))
- legacyrates.rmempty = false
- legacyrates.default = "1"
-
- s:taboption("advanced", Value, "distance", translate("Distance Optimization"),
- translate("Distance to farthest network member in meters."))
-
- -- external antenna profiles
- local eal = iw and iw.extant
- if eal and #eal > 0 then
- ea = s:taboption("advanced", ListValue, "extant", translate("Antenna Configuration"))
- for _, eap in ipairs(eal) do
- ea:value(eap.id, "%s (%s)" %{ eap.name, eap.description })
- if eap.selected then
- ea.default = eap.id
- end
- end
- end
-
- s:taboption("advanced", Value, "frag", translate("Fragmentation Threshold"))
- s:taboption("advanced", Value, "rts", translate("RTS/CTS Threshold"))
-
- s:taboption("advanced", Flag, "noscan", translate("Force 40MHz mode"),
- translate("Always use 40MHz channels even if the secondary channel overlaps. Using this option does not comply with IEEE 802.11n-2009!")).optional = true
-
- beacon_int = s:taboption("advanced", Value, "beacon_int", translate("Beacon Interval"))
- beacon_int.optional = true
- beacon_int.placeholder = 100
- beacon_int.datatype = "range(15,65535)"
-end
-
-
-------------------- Broadcom Device ------------------
-
-if hwtype == "broadcom" then
- tp = s:taboption("general",
- (#tx_power_list > 0) and ListValue or Value,
- "txpower", translate("Transmit Power"), "dBm")
-
- tp.rmempty = true
- tp.default = tx_power_cur
-
- function tp.cfgvalue(...)
- return txpower_current(Value.cfgvalue(...), tx_power_list)
- end
-
- tp:value("", translate("auto"))
- for _, p in ipairs(tx_power_list) do
- tp:value(p.driver_dbm, "%i dBm (%i mW)"
- %{ p.display_dbm, p.display_mw })
- end
-
- mode = s:taboption("advanced", ListValue, "hwmode", translate("Band"))
- if hw_modes.b then
- mode:value("11b", "2.4GHz (802.11b)")
- if hw_modes.g then
- mode:value("11bg", "2.4GHz (802.11b+g)")
- end
- end
- if hw_modes.g then
- mode:value("11g", "2.4GHz (802.11g)")
- mode:value("11gst", "2.4GHz (802.11g + Turbo)")
- mode:value("11lrs", "2.4GHz (802.11g Limited Rate Support)")
- end
- if hw_modes.a then mode:value("11a", "5GHz (802.11a)") end
- if hw_modes.n then
- if hw_modes.g then
- mode:value("11ng", "2.4GHz (802.11g+n)")
- mode:value("11n", "2.4GHz (802.11n)")
- end
- if hw_modes.a then
- mode:value("11na", "5GHz (802.11a+n)")
- mode:value("11n", "5GHz (802.11n)")
- end
- htmode = s:taboption("advanced", ListValue, "htmode", translate("HT mode (802.11n)"))
- htmode:depends("hwmode", "11ng")
- htmode:depends("hwmode", "11na")
- htmode:depends("hwmode", "11n")
- htmode:value("HT20", "20MHz")
- htmode:value("HT40", "40MHz")
- end
-
- ant1 = s:taboption("advanced", ListValue, "txantenna", translate("Transmitter Antenna"))
- ant1.widget = "radio"
- ant1:depends("diversity", "")
- ant1:value("3", translate("auto"))
- ant1:value("0", translate("Antenna 1"))
- ant1:value("1", translate("Antenna 2"))
-
- ant2 = s:taboption("advanced", ListValue, "rxantenna", translate("Receiver Antenna"))
- ant2.widget = "radio"
- ant2:depends("diversity", "")
- ant2:value("3", translate("auto"))
- ant2:value("0", translate("Antenna 1"))
- ant2:value("1", translate("Antenna 2"))
-
- s:taboption("advanced", Flag, "frameburst", translate("Frame Bursting"))
-
- s:taboption("advanced", Value, "distance", translate("Distance Optimization"))
- --s:option(Value, "slottime", translate("Slot time"))
-
- s:taboption("advanced", Value, "country", translate("Country Code"))
- s:taboption("advanced", Value, "maxassoc", translate("Connection Limit"))
-end
-
-
---------------------- HostAP Device ---------------------
-
-if hwtype == "prism2" then
- s:taboption("advanced", Value, "txpower", translate("Transmit Power"), "att units").rmempty = true
-
- s:taboption("advanced", Flag, "diversity", translate("Diversity")).rmempty = false
-
- s:taboption("advanced", Value, "txantenna", translate("Transmitter Antenna"))
- s:taboption("advanced", Value, "rxantenna", translate("Receiver Antenna"))
-end
-
-
------------------------ Interface -----------------------
-
-s = m:section(NamedSection, wnet.sid, "wifi-iface", translate("Interface Configuration"))
-s.addremove = false
-s.anonymous = true
-s.defaults.device = wdev:name()
-
-s:tab("general", translate("General Setup"))
-s:tab("encryption", translate("Wireless Security"))
-s:tab("macfilter", translate("MAC-Filter"))
-s:tab("advanced", translate("Advanced Settings"))
-
-mode = s:taboption("general", ListValue, "mode", translate("Mode"))
-mode.override_values = true
-mode:value("ap", translate("Access Point"))
-mode:value("sta", translate("Client"))
-mode:value("adhoc", translate("Ad-Hoc"))
-
-meshid = s:taboption("general", Value, "mesh_id", translate("Mesh Id"))
-meshid:depends({mode="mesh"})
-
-meshfwd = s:taboption("advanced", Flag, "mesh_fwding", translate("Forward mesh peer traffic"))
-meshfwd.rmempty = false
-meshfwd.default = "1"
-meshfwd:depends({mode="mesh"})
-
-ssid = s:taboption("general", Value, "ssid", translate("ESSID"))
-ssid.datatype = "maxlength(32)"
-ssid:depends({mode="ap"})
-ssid:depends({mode="sta"})
-ssid:depends({mode="adhoc"})
-ssid:depends({mode="ahdemo"})
-ssid:depends({mode="monitor"})
-ssid:depends({mode="ap-wds"})
-ssid:depends({mode="sta-wds"})
-ssid:depends({mode="wds"})
-
-bssid = s:taboption("general", Value, "bssid", translate("BSSID"))
-
-network = s:taboption("general", Value, "network", translate("Network"),
- translate("Choose the network(s) you want to attach to this wireless interface or " ..
- "fill out the create field to define a new network."))
-
-network.rmempty = true
-network.template = "cbi/network_netlist"
-network.widget = "checkbox"
-network.novirtual = true
-
-function network.write(self, section, value)
- local i = nw:get_interface(section)
- if i then
- local _, net, old, new = nil, nil, {}, {}
-
- for _, net in ipairs(i:get_networks()) do
- old[net:name()] = true
- end
-
- for net in ut.imatch(value) do
- new[net] = true
- if not old[net] then
- local n = nw:get_network(net) or nw:add_network(net, { proto = "none" })
- if n then
- if not n:is_empty() then
- n:set("type", "bridge")
- end
- n:add_interface(i)
- end
- end
- end
-
- for net, _ in pairs(old) do
- if not new[net] then
- local n = nw:get_network(net)
- if n then
- n:del_interface(i)
- end
- end
- end
- end
-end
-
--------------------- MAC80211 Interface ----------------------
-
-if hwtype == "mac80211" then
- if fs.access("/usr/sbin/iw") then
- mode:value("mesh", "802.11s")
- end
-
- mode:value("ahdemo", translate("Pseudo Ad-Hoc (ahdemo)"))
- mode:value("monitor", translate("Monitor"))
- bssid:depends({mode="adhoc"})
- bssid:depends({mode="sta"})
- bssid:depends({mode="sta-wds"})
-
- mp = s:taboption("macfilter", ListValue, "macfilter", translate("MAC-Address Filter"))
- mp:depends({mode="ap"})
- mp:depends({mode="ap-wds"})
- mp:value("", translate("disable"))
- mp:value("allow", translate("Allow listed only"))
- mp:value("deny", translate("Allow all except listed"))
-
- ml = s:taboption("macfilter", DynamicList, "maclist", translate("MAC-List"))
- ml.datatype = "macaddr"
- ml:depends({macfilter="allow"})
- ml:depends({macfilter="deny"})
- nt.mac_hints(function(mac, name) ml:value(mac, "%s (%s)" %{ mac, name }) end)
-
- mode:value("ap-wds", "%s (%s)" % {translate("Access Point"), translate("WDS")})
- mode:value("sta-wds", "%s (%s)" % {translate("Client"), translate("WDS")})
-
- function mode.write(self, section, value)
- if value == "ap-wds" then
- ListValue.write(self, section, "ap")
- m.uci:set("wireless", section, "wds", 1)
- elseif value == "sta-wds" then
- ListValue.write(self, section, "sta")
- m.uci:set("wireless", section, "wds", 1)
- else
- ListValue.write(self, section, value)
- m.uci:delete("wireless", section, "wds")
- end
- end
-
- function mode.cfgvalue(self, section)
- local mode = ListValue.cfgvalue(self, section)
- local wds = m.uci:get("wireless", section, "wds") == "1"
-
- if mode == "ap" and wds then
- return "ap-wds"
- elseif mode == "sta" and wds then
- return "sta-wds"
- else
- return mode
- end
- end
-
- hidden = s:taboption("general", Flag, "hidden", translate("Hide ESSID"))
- hidden:depends({mode="ap"})
- hidden:depends({mode="ap-wds"})
-
- wmm = s:taboption("general", Flag, "wmm", translate("WMM Mode"))
- wmm:depends({mode="ap"})
- wmm:depends({mode="ap-wds"})
- wmm.default = wmm.enabled
-
- isolate = s:taboption("advanced", Flag, "isolate", translate("Isolate Clients"),
- translate("Prevents client-to-client communication"))
- isolate:depends({mode="ap"})
- isolate:depends({mode="ap-wds"})
-
- ifname = s:taboption("advanced", Value, "ifname", translate("Interface name"), translate("Override default interface name"))
- ifname.optional = true
-
- short_preamble = s:taboption("advanced", Flag, "short_preamble", translate("Short Preamble"))
- short_preamble.default = short_preamble.enabled
-
- dtim_period = s:taboption("advanced", Value, "dtim_period", translate("DTIM Interval"), translate("Delivery Traffic Indication Message Interval"))
- dtim_period.optional = true
- dtim_period.placeholder = 2
- dtim_period.datatype = "range(1,255)"
-
- disassoc_low_ack = s:taboption("advanced", Flag, "disassoc_low_ack", translate("Disassociate On Low Acknowledgement"),
- translate("Allow AP mode to disconnect STAs based on low ACK condition"))
- disassoc_low_ack.default = disassoc_low_ack.enabled
-end
-
-
--------------------- Broadcom Interface ----------------------
-
-if hwtype == "broadcom" then
- mode:value("wds", translate("WDS"))
- mode:value("monitor", translate("Monitor"))
-
- hidden = s:taboption("general", Flag, "hidden", translate("Hide ESSID"))
- hidden:depends({mode="ap"})
- hidden:depends({mode="adhoc"})
- hidden:depends({mode="wds"})
-
- isolate = s:taboption("advanced", Flag, "isolate", translate("Separate Clients"),
- translate("Prevents client-to-client communication"))
- isolate:depends({mode="ap"})
-
- s:taboption("advanced", Flag, "doth", "802.11h")
- s:taboption("advanced", Flag, "wmm", translate("WMM Mode"))
-
- bssid:depends({mode="wds"})
- bssid:depends({mode="adhoc"})
-end
-
-
------------------------ HostAP Interface ---------------------
-
-if hwtype == "prism2" then
- mode:value("wds", translate("WDS"))
- mode:value("monitor", translate("Monitor"))
-
- hidden = s:taboption("general", Flag, "hidden", translate("Hide ESSID"))
- hidden:depends({mode="ap"})
- hidden:depends({mode="adhoc"})
- hidden:depends({mode="wds"})
-
- bssid:depends({mode="sta"})
-
- mp = s:taboption("macfilter", ListValue, "macpolicy", translate("MAC-Address Filter"))
- mp:value("", translate("disable"))
- mp:value("allow", translate("Allow listed only"))
- mp:value("deny", translate("Allow all except listed"))
- ml = s:taboption("macfilter", DynamicList, "maclist", translate("MAC-List"))
- ml:depends({macpolicy="allow"})
- ml:depends({macpolicy="deny"})
- nt.mac_hints(function(mac, name) ml:value(mac, "%s (%s)" %{ mac, name }) end)
-
- s:taboption("advanced", Value, "rate", translate("Transmission Rate"))
- s:taboption("advanced", Value, "frag", translate("Fragmentation Threshold"))
- s:taboption("advanced", Value, "rts", translate("RTS/CTS Threshold"))
-end
-
-
-------------------- WiFI-Encryption -------------------
-
-encr = s:taboption("encryption", ListValue, "encryption", translate("Encryption"))
-encr.override_values = true
-encr.override_depends = true
-encr:depends({mode="ap"})
-encr:depends({mode="sta"})
-encr:depends({mode="adhoc"})
-encr:depends({mode="ahdemo"})
-encr:depends({mode="ap-wds"})
-encr:depends({mode="sta-wds"})
-encr:depends({mode="mesh"})
-
-cipher = s:taboption("encryption", ListValue, "cipher", translate("Cipher"))
-cipher:depends({encryption="wpa"})
-cipher:depends({encryption="wpa2"})
-cipher:depends({encryption="psk"})
-cipher:depends({encryption="psk2"})
-cipher:depends({encryption="wpa-mixed"})
-cipher:depends({encryption="psk-mixed"})
-cipher:value("auto", translate("auto"))
-cipher:value("ccmp", translate("Force CCMP (AES)"))
-cipher:value("tkip", translate("Force TKIP"))
-cipher:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)"))
-
-function encr.cfgvalue(self, section)
- local v = tostring(ListValue.cfgvalue(self, section))
- if v == "wep" then
- return "wep-open"
- elseif v and v:match("%+") then
- return (v:gsub("%+.+$", ""))
- end
- return v
-end
-
-function encr.write(self, section, value)
- local e = tostring(encr:formvalue(section))
- local c = tostring(cipher:formvalue(section))
- if value == "wpa" or value == "wpa2" then
- self.map.uci:delete("wireless", section, "key")
- end
- if e and (c == "tkip" or c == "ccmp" or c == "tkip+ccmp") then
- e = e .. "+" .. c
- end
- self.map:set(section, "encryption", e)
-end
-
-function cipher.cfgvalue(self, section)
- local v = tostring(ListValue.cfgvalue(encr, section))
- if v and v:match("%+") then
- v = v:gsub("^[^%+]+%+", "")
- if v == "aes" then v = "ccmp"
- elseif v == "tkip+aes" then v = "tkip+ccmp"
- elseif v == "aes+tkip" then v = "tkip+ccmp"
- elseif v == "ccmp+tkip" then v = "tkip+ccmp"
- end
- end
- return v
-end
-
-function cipher.write(self, section)
- return encr:write(section)
-end
-
-
-encr:value("none", "No Encryption")
-encr:value("wep-open", translate("WEP Open System"), {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"}, {mode="ahdemo"}, {mode="wds"})
-encr:value("wep-shared", translate("WEP Shared Key"), {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"}, {mode="ahdemo"}, {mode="wds"})
-
-if hwtype == "mac80211" or hwtype == "prism2" then
- local supplicant = fs.access("/usr/sbin/wpa_supplicant")
- local hostapd = fs.access("/usr/sbin/hostapd")
-
- -- Probe EAP support
- local has_ap_eap = (os.execute("hostapd -veap >/dev/null 2>/dev/null") == 0)
- local has_sta_eap = (os.execute("wpa_supplicant -veap >/dev/null 2>/dev/null") == 0)
-
- if hostapd and supplicant then
- encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"})
- encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"})
- encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"})
- if has_ap_eap and has_sta_eap then
- encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
- encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
- end
- elseif hostapd and not supplicant then
- encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="ap-wds"})
- encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="ap-wds"})
- encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="ap-wds"})
- if has_ap_eap then
- encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="ap-wds"})
- encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="ap-wds"})
- end
- encr.description = translate(
- "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
- "and ad-hoc mode) to be installed."
- )
- elseif not hostapd and supplicant then
- encr:value("psk", "WPA-PSK", {mode="sta"}, {mode="sta-wds"}, {mode="adhoc"})
- encr:value("psk2", "WPA2-PSK", {mode="sta"}, {mode="sta-wds"}, {mode="adhoc"})
- encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="sta"}, {mode="sta-wds"}, {mode="adhoc"})
- if has_sta_eap then
- encr:value("wpa", "WPA-EAP", {mode="sta"}, {mode="sta-wds"})
- encr:value("wpa2", "WPA2-EAP", {mode="sta"}, {mode="sta-wds"})
- end
- encr.description = translate(
- "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
- "and ad-hoc mode) to be installed."
- )
- else
- encr.description = translate(
- "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
- "and ad-hoc mode) to be installed."
- )
- end
-elseif hwtype == "broadcom" then
- encr:value("psk", "WPA-PSK")
- encr:value("psk2", "WPA2-PSK")
- encr:value("psk+psk2", "WPA-PSK/WPA2-PSK Mixed Mode")
-end
-
-auth_server = s:taboption("encryption", Value, "auth_server", translate("Radius-Authentication-Server"))
-auth_server:depends({mode="ap", encryption="wpa"})
-auth_server:depends({mode="ap", encryption="wpa2"})
-auth_server:depends({mode="ap-wds", encryption="wpa"})
-auth_server:depends({mode="ap-wds", encryption="wpa2"})
-auth_server.rmempty = true
-auth_server.datatype = "host(0)"
-
-auth_port = s:taboption("encryption", Value, "auth_port", translate("Radius-Authentication-Port"), translatef("Default %d", 1812))
-auth_port:depends({mode="ap", encryption="wpa"})
-auth_port:depends({mode="ap", encryption="wpa2"})
-auth_port:depends({mode="ap-wds", encryption="wpa"})
-auth_port:depends({mode="ap-wds", encryption="wpa2"})
-auth_port.rmempty = true
-auth_port.datatype = "port"
-
-auth_secret = s:taboption("encryption", Value, "auth_secret", translate("Radius-Authentication-Secret"))
-auth_secret:depends({mode="ap", encryption="wpa"})
-auth_secret:depends({mode="ap", encryption="wpa2"})
-auth_secret:depends({mode="ap-wds", encryption="wpa"})
-auth_secret:depends({mode="ap-wds", encryption="wpa2"})
-auth_secret.rmempty = true
-auth_secret.password = true
-
-acct_server = s:taboption("encryption", Value, "acct_server", translate("Radius-Accounting-Server"))
-acct_server:depends({mode="ap", encryption="wpa"})
-acct_server:depends({mode="ap", encryption="wpa2"})
-acct_server:depends({mode="ap-wds", encryption="wpa"})
-acct_server:depends({mode="ap-wds", encryption="wpa2"})
-acct_server.rmempty = true
-acct_server.datatype = "host(0)"
-
-acct_port = s:taboption("encryption", Value, "acct_port", translate("Radius-Accounting-Port"), translatef("Default %d", 1813))
-acct_port:depends({mode="ap", encryption="wpa"})
-acct_port:depends({mode="ap", encryption="wpa2"})
-acct_port:depends({mode="ap-wds", encryption="wpa"})
-acct_port:depends({mode="ap-wds", encryption="wpa2"})
-acct_port.rmempty = true
-acct_port.datatype = "port"
-
-acct_secret = s:taboption("encryption", Value, "acct_secret", translate("Radius-Accounting-Secret"))
-acct_secret:depends({mode="ap", encryption="wpa"})
-acct_secret:depends({mode="ap", encryption="wpa2"})
-acct_secret:depends({mode="ap-wds", encryption="wpa"})
-acct_secret:depends({mode="ap-wds", encryption="wpa2"})
-acct_secret.rmempty = true
-acct_secret.password = true
-
-wpakey = s:taboption("encryption", Value, "_wpa_key", translate("Key"))
-wpakey:depends("encryption", "psk")
-wpakey:depends("encryption", "psk2")
-wpakey:depends("encryption", "psk+psk2")
-wpakey:depends("encryption", "psk-mixed")
-wpakey.datatype = "wpakey"
-wpakey.rmempty = true
-wpakey.password = true
-
-wpakey.cfgvalue = function(self, section, value)
- local key = m.uci:get("wireless", section, "key")
- if key == "1" or key == "2" or key == "3" or key == "4" then
- return nil
- end
- return key
-end
-
-wpakey.write = function(self, section, value)
- self.map.uci:set("wireless", section, "key", value)
- self.map.uci:delete("wireless", section, "key1")
-end
-
-
-wepslot = s:taboption("encryption", ListValue, "_wep_key", translate("Used Key Slot"))
-wepslot:depends("encryption", "wep-open")
-wepslot:depends("encryption", "wep-shared")
-wepslot:value("1", translatef("Key #%d", 1))
-wepslot:value("2", translatef("Key #%d", 2))
-wepslot:value("3", translatef("Key #%d", 3))
-wepslot:value("4", translatef("Key #%d", 4))
-
-wepslot.cfgvalue = function(self, section)
- local slot = tonumber(m.uci:get("wireless", section, "key"))
- if not slot or slot < 1 or slot > 4 then
- return 1
- end
- return slot
-end
-
-wepslot.write = function(self, section, value)
- self.map.uci:set("wireless", section, "key", value)
-end
-
-local slot
-for slot=1,4 do
- wepkey = s:taboption("encryption", Value, "key" .. slot, translatef("Key #%d", slot))
- wepkey:depends("encryption", "wep-open")
- wepkey:depends("encryption", "wep-shared")
- wepkey.datatype = "wepkey"
- wepkey.rmempty = true
- wepkey.password = true
-
- function wepkey.write(self, section, value)
- if value and (#value == 5 or #value == 13) then
- value = "s:" .. value
- end
- return Value.write(self, section, value)
- end
-end
-
-
-if hwtype == "mac80211" or hwtype == "prism2" then
-
- -- Probe 802.11r support (and EAP support as a proxy for Openwrt)
- local has_80211r = (os.execute("hostapd -v11r 2>/dev/null || hostapd -veap 2>/dev/null") == 0)
-
- ieee80211r = s:taboption("encryption", Flag, "ieee80211r",
- translate("802.11r Fast Transition"),
- translate("Enables fast roaming among access points that belong " ..
- "to the same Mobility Domain"))
- ieee80211r:depends({mode="ap", encryption="wpa"})
- ieee80211r:depends({mode="ap", encryption="wpa2"})
- ieee80211r:depends({mode="ap-wds", encryption="wpa"})
- ieee80211r:depends({mode="ap-wds", encryption="wpa2"})
- if has_80211r then
- ieee80211r:depends({mode="ap", encryption="psk"})
- ieee80211r:depends({mode="ap", encryption="psk2"})
- ieee80211r:depends({mode="ap", encryption="psk-mixed"})
- ieee80211r:depends({mode="ap-wds", encryption="psk"})
- ieee80211r:depends({mode="ap-wds", encryption="psk2"})
- ieee80211r:depends({mode="ap-wds", encryption="psk-mixed"})
- end
- ieee80211r.rmempty = true
-
- nasid = s:taboption("encryption", Value, "nasid", translate("NAS ID"),
- translate("Used for two different purposes: RADIUS NAS ID and " ..
- "802.11r R0KH-ID. Not needed with normal WPA(2)-PSK."))
- nasid:depends({mode="ap", encryption="wpa"})
- nasid:depends({mode="ap", encryption="wpa2"})
- nasid:depends({mode="ap-wds", encryption="wpa"})
- nasid:depends({mode="ap-wds", encryption="wpa2"})
- nasid:depends({ieee80211r="1"})
- nasid.rmempty = true
-
- mobility_domain = s:taboption("encryption", Value, "mobility_domain",
- translate("Mobility Domain"),
- translate("4-character hexadecimal ID"))
- mobility_domain:depends({ieee80211r="1"})
- mobility_domain.placeholder = "4f57"
- mobility_domain.datatype = "and(hexstring,rangelength(4,4))"
- mobility_domain.rmempty = true
-
- reassociation_deadline = s:taboption("encryption", Value, "reassociation_deadline",
- translate("Reassociation Deadline"),
- translate("time units (TUs / 1.024 ms) [1000-65535]"))
- reassociation_deadline:depends({ieee80211r="1"})
- reassociation_deadline.placeholder = "1000"
- reassociation_deadline.datatype = "range(1000,65535)"
- reassociation_deadline.rmempty = true
-
- ft_protocol = s:taboption("encryption", ListValue, "ft_over_ds", translate("FT protocol"))
- ft_protocol:depends({ieee80211r="1"})
- ft_protocol:value("1", translatef("FT over DS"))
- ft_protocol:value("0", translatef("FT over the Air"))
- ft_protocol.rmempty = true
-
- ft_psk_generate_local = s:taboption("encryption", Flag, "ft_psk_generate_local",
- translate("Generate PMK locally"),
- translate("When using a PSK, the PMK can be generated locally without inter AP communications"))
- ft_psk_generate_local:depends({ieee80211r="1"})
-
- r0_key_lifetime = s:taboption("encryption", Value, "r0_key_lifetime",
- translate("R0 Key Lifetime"), translate("minutes"))
- r0_key_lifetime:depends({ieee80211r="1", ft_psk_generate_local=""})
- r0_key_lifetime.placeholder = "10000"
- r0_key_lifetime.datatype = "uinteger"
- r0_key_lifetime.rmempty = true
-
- r1_key_holder = s:taboption("encryption", Value, "r1_key_holder",
- translate("R1 Key Holder"),
- translate("6-octet identifier as a hex string - no colons"))
- r1_key_holder:depends({ieee80211r="1", ft_psk_generate_local=""})
- r1_key_holder.placeholder = "00004f577274"
- r1_key_holder.datatype = "and(hexstring,rangelength(12,12))"
- r1_key_holder.rmempty = true
-
- pmk_r1_push = s:taboption("encryption", Flag, "pmk_r1_push", translate("PMK R1 Push"))
- pmk_r1_push:depends({ieee80211r="1", ft_psk_generate_local=""})
- pmk_r1_push.placeholder = "0"
- pmk_r1_push.rmempty = true
-
- r0kh = s:taboption("encryption", DynamicList, "r0kh", translate("External R0 Key Holder List"),
- translate("List of R0KHs in the same Mobility Domain. " ..
- " Format: MAC-address,NAS-Identifier,128-bit key as hex string. " ..
- " This list is used to map R0KH-ID (NAS Identifier) to a destination " ..
- "MAC address when requesting PMK-R1 key from the R0KH that the STA " ..
- "used during the Initial Mobility Domain Association."))
- r0kh:depends({ieee80211r="1", ft_psk_generate_local=""})
- r0kh.rmempty = true
-
- r1kh = s:taboption("encryption", DynamicList, "r1kh", translate("External R1 Key Holder List"),
- translate ("List of R1KHs in the same Mobility Domain. "..
- " Format: MAC-address,R1KH-ID as 6 octets with colons,128-bit key as hex string. "..
- " This list is used to map R1KH-ID to a destination MAC address " ..
- "when sending PMK-R1 key from the R0KH. This is also the " ..
- "list of authorized R1KHs in the MD that can request PMK-R1 keys."))
- r1kh:depends({ieee80211r="1", ft_psk_generate_local=""})
- r1kh.rmempty = true
- -- End of 802.11r options
-
- eaptype = s:taboption("encryption", ListValue, "eap_type", translate("EAP-Method"))
- eaptype:value("tls", "TLS")
- eaptype:value("ttls", "TTLS")
- eaptype:value("peap", "PEAP")
- eaptype:value("fast", "FAST")
- eaptype:depends({mode="sta", encryption="wpa"})
- eaptype:depends({mode="sta", encryption="wpa2"})
- eaptype:depends({mode="sta-wds", encryption="wpa"})
- eaptype:depends({mode="sta-wds", encryption="wpa2"})
-
- cacert = s:taboption("encryption", FileUpload, "ca_cert", translate("Path to CA-Certificate"))
- cacert:depends({mode="sta", encryption="wpa"})
- cacert:depends({mode="sta", encryption="wpa2"})
- cacert:depends({mode="sta-wds", encryption="wpa"})
- cacert:depends({mode="sta-wds", encryption="wpa2"})
- cacert.rmempty = true
-
- clientcert = s:taboption("encryption", FileUpload, "client_cert", translate("Path to Client-Certificate"))
- clientcert:depends({mode="sta", eap_type="tls", encryption="wpa"})
- clientcert:depends({mode="sta", eap_type="tls", encryption="wpa2"})
- clientcert:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
- clientcert:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
-
- privkey = s:taboption("encryption", FileUpload, "priv_key", translate("Path to Private Key"))
- privkey:depends({mode="sta", eap_type="tls", encryption="wpa2"})
- privkey:depends({mode="sta", eap_type="tls", encryption="wpa"})
- privkey:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
- privkey:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
-
- privkeypwd = s:taboption("encryption", Value, "priv_key_pwd", translate("Password of Private Key"))
- privkeypwd:depends({mode="sta", eap_type="tls", encryption="wpa2"})
- privkeypwd:depends({mode="sta", eap_type="tls", encryption="wpa"})
- privkeypwd:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
- privkeypwd:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
- privkeypwd.rmempty = true
- privkeypwd.password = true
-
- auth = s:taboption("encryption", ListValue, "auth", translate("Authentication"))
- auth:value("PAP", "PAP", {eap_type="ttls"})
- auth:value("CHAP", "CHAP", {eap_type="ttls"})
- auth:value("MSCHAP", "MSCHAP", {eap_type="ttls"})
- auth:value("MSCHAPV2", "MSCHAPv2", {eap_type="ttls"})
- auth:value("EAP-GTC")
- auth:value("EAP-MD5")
- auth:value("EAP-MSCHAPV2")
- auth:value("EAP-TLS")
- auth:depends({mode="sta", eap_type="fast", encryption="wpa2"})
- auth:depends({mode="sta", eap_type="fast", encryption="wpa"})
- auth:depends({mode="sta", eap_type="peap", encryption="wpa2"})
- auth:depends({mode="sta", eap_type="peap", encryption="wpa"})
- auth:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
- auth:depends({mode="sta", eap_type="ttls", encryption="wpa"})
- auth:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
- auth:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
- auth:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
- auth:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
- auth:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
- auth:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
-
- cacert2 = s:taboption("encryption", FileUpload, "ca_cert2", translate("Path to inner CA-Certificate"))
- cacert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
- cacert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
- cacert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
- cacert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
-
- clientcert2 = s:taboption("encryption", FileUpload, "client_cert2", translate("Path to inner Client-Certificate"))
- clientcert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
- clientcert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
- clientcert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
- clientcert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
-
- privkey2 = s:taboption("encryption", FileUpload, "priv_key2", translate("Path to inner Private Key"))
- privkey2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
- privkey2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
- privkey2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
- privkey2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
-
- privkeypwd2 = s:taboption("encryption", Value, "priv_key2_pwd", translate("Password of inner Private Key"))
- privkeypwd2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
- privkeypwd2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
- privkeypwd2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
- privkeypwd2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
- privkeypwd2.rmempty = true
- privkeypwd2.password = true
-
- identity = s:taboption("encryption", Value, "identity", translate("Identity"))
- identity:depends({mode="sta", eap_type="fast", encryption="wpa2"})
- identity:depends({mode="sta", eap_type="fast", encryption="wpa"})
- identity:depends({mode="sta", eap_type="peap", encryption="wpa2"})
- identity:depends({mode="sta", eap_type="peap", encryption="wpa"})
- identity:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
- identity:depends({mode="sta", eap_type="ttls", encryption="wpa"})
- identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
- identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
- identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
- identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
- identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
- identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
- identity:depends({mode="sta", eap_type="tls", encryption="wpa2"})
- identity:depends({mode="sta", eap_type="tls", encryption="wpa"})
- identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
- identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
-
- anonymous_identity = s:taboption("encryption", Value, "anonymous_identity", translate("Anonymous Identity"))
- anonymous_identity:depends({mode="sta", eap_type="fast", encryption="wpa2"})
- anonymous_identity:depends({mode="sta", eap_type="fast", encryption="wpa"})
- anonymous_identity:depends({mode="sta", eap_type="peap", encryption="wpa2"})
- anonymous_identity:depends({mode="sta", eap_type="peap", encryption="wpa"})
- anonymous_identity:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
- anonymous_identity:depends({mode="sta", eap_type="ttls", encryption="wpa"})
- anonymous_identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
- anonymous_identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
- anonymous_identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
- anonymous_identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
- anonymous_identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
- anonymous_identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
- anonymous_identity:depends({mode="sta", eap_type="tls", encryption="wpa2"})
- anonymous_identity:depends({mode="sta", eap_type="tls", encryption="wpa"})
- anonymous_identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
- anonymous_identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
-
- password = s:taboption("encryption", Value, "password", translate("Password"))
- password:depends({mode="sta", eap_type="fast", encryption="wpa2"})
- password:depends({mode="sta", eap_type="fast", encryption="wpa"})
- password:depends({mode="sta", eap_type="peap", encryption="wpa2"})
- password:depends({mode="sta", eap_type="peap", encryption="wpa"})
- password:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
- password:depends({mode="sta", eap_type="ttls", encryption="wpa"})
- password:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
- password:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
- password:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
- password:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
- password:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
- password:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
- password.rmempty = true
- password.password = true
-end
-
--- ieee802.11w options
-if hwtype == "mac80211" then
- local has_80211w = (os.execute("hostapd -v11w 2>/dev/null || hostapd -veap 2>/dev/null") == 0)
- if has_80211w then
- ieee80211w = s:taboption("encryption", ListValue, "ieee80211w",
- translate("802.11w Management Frame Protection"),
- translate("Requires the 'full' version of wpad/hostapd " ..
- "and support from the wifi driver (as of Feb 2017: " ..
- "ath9k and ath10k, in LEDE also mwlwifi and mt76)"))
- ieee80211w.default = ""
- ieee80211w.rmempty = true
- ieee80211w:value("", translate("Disabled (default)"))
- ieee80211w:value("1", translate("Optional"))
- ieee80211w:value("2", translate("Required"))
- ieee80211w:depends({mode="ap", encryption="wpa2"})
- ieee80211w:depends({mode="ap-wds", encryption="wpa2"})
- ieee80211w:depends({mode="ap", encryption="psk2"})
- ieee80211w:depends({mode="ap", encryption="psk-mixed"})
- ieee80211w:depends({mode="ap-wds", encryption="psk2"})
- ieee80211w:depends({mode="ap-wds", encryption="psk-mixed"})
-
- max_timeout = s:taboption("encryption", Value, "ieee80211w_max_timeout",
- translate("802.11w maximum timeout"),
- translate("802.11w Association SA Query maximum timeout"))
- max_timeout:depends({ieee80211w="1"})
- max_timeout:depends({ieee80211w="2"})
- max_timeout.datatype = "uinteger"
- max_timeout.placeholder = "1000"
- max_timeout.rmempty = true
-
- retry_timeout = s:taboption("encryption", Value, "ieee80211w_retry_timeout",
- translate("802.11w retry timeout"),
- translate("802.11w Association SA Query retry timeout"))
- retry_timeout:depends({ieee80211w="1"})
- retry_timeout:depends({ieee80211w="2"})
- retry_timeout.datatype = "uinteger"
- retry_timeout.placeholder = "201"
- retry_timeout.rmempty = true
- end
-
- key_retries = s:taboption("encryption", Flag, "wpa_disable_eapol_key_retries",
- translate("Enable key reinstallation (KRACK) countermeasures"),
- translate("Complicates key reinstallation attacks on the client side by disabling retransmission of EAPOL-Key frames that are used to install keys. This workaround might cause interoperability issues and reduced robustness of key negotiation especially in environments with heavy traffic load."))
-
- key_retries:depends({mode="ap", encryption="wpa2"})
- key_retries:depends({mode="ap", encryption="psk2"})
- key_retries:depends({mode="ap", encryption="psk-mixed"})
- key_retries:depends({mode="ap-wds", encryption="wpa2"})
- key_retries:depends({mode="ap-wds", encryption="psk2"})
- key_retries:depends({mode="ap-wds", encryption="psk-mixed"})
-end
-
-if hwtype == "mac80211" or hwtype == "prism2" then
- local wpasupplicant = fs.access("/usr/sbin/wpa_supplicant")
- local hostcli = fs.access("/usr/sbin/hostapd_cli")
- if hostcli and wpasupplicant then
- wps = s:taboption("encryption", Flag, "wps_pushbutton", translate("Enable WPS pushbutton, requires WPA(2)-PSK"))
- wps.enabled = "1"
- wps.disabled = "0"
- wps.rmempty = false
- wps:depends("encryption", "psk")
- wps:depends("encryption", "psk2")
- wps:depends("encryption", "psk-mixed")
- end
-end
-
-return m
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_add.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_add.lua
deleted file mode 100644
index e8a3058826..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_add.lua
+++ /dev/null
@@ -1,168 +0,0 @@
--- Copyright 2009 Jo-Philipp Wich
--- 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: A-Z, a-z, " ..
- "0-9 and _"
- ))
-
-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 unspecified to remove the interface from the associated zone or fill out the create 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua
deleted file mode 100644
index ad20f09187..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua
+++ /dev/null
@@ -1,223 +0,0 @@
--- Copyright 2018 Jo-Philipp Wich
--- 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, [[
-
-
-
-
-
- <%=dev:name()%>
-
-
- <%=hw%>
-
-
-
-
-
-
-
-
-
-
-
-
-
- <% if #wnets > 0 then %>
- <% for i, net in ipairs(wnets) do local disabled = (dev:get("disabled") == "1" or net:get("disabled") == "1") %>
-
-
- .png" /> 0%
-
-
">
- <%= disabled and translate("Wireless is disabled") or translate("Collecting data...") %>
-
-
-
- <% if disabled then %>
-
-
- <% else %>
-
-
- <% end %>
-
-
-
-
-
-
-
-
- <% end %>
- <% else %>
-
-
- <%:No network configured on this device%>
-
-
- <% end %>
-
-
-
-]])
-
-
-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([[
-
-
<%:Package libiwinfo required!%>
-
<%_The libiwinfo-lua package is not installed. You must install this component for working wireless configuration!%>
-
- ]])
- 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([[
-
<%:Associated Stations%>
- <%+admin_network/wifi_assoclist%>
- ]])
-end
-
-return m
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_status/processes.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_status/processes.lua
deleted file mode 100644
index 0a6e48fd8e..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_status/processes.lua
+++ /dev/null
@@ -1,34 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2008 Jo-Philipp Wich
--- 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
\ No newline at end of file
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/admin.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/admin.lua
deleted file mode 100644
index 6c1c1235c5..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/admin.lua
+++ /dev/null
@@ -1,122 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2011 Jo-Philipp Wich
--- 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 SSH network shell access and an integrated SCP 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 Dropbear instance"))
-
-pt.datatype = "port"
-pt.default = 22
-
-
-pa = s:option(Flag, "PasswordAuth", translate("Password authentication"),
- translate("Allow SSH 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 root 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
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/backupfiles.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/backupfiles.lua
deleted file mode 100644
index ee2401e93d..0000000000
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/backupfiles.lua
+++ /dev/null
@@ -1,80 +0,0 @@
--- Copyright 2008 Steven Barth
--- Copyright 2011 Jo-Philipp Wich
--- 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 = { "
" }
-
- while true do
- local ln = list:read("*l")
- if not ln then
- break
- else
- files[#files+1] = "
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/connections.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/connections.htm
deleted file mode 100644
index 0a0db3be78..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/connections.htm
+++ /dev/null
@@ -1,376 +0,0 @@
-<%#
- Copyright 2010 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-<%+header%>
-
-
-
-
<%:Realtime Connections%>
-
-
<%:This page gives an overview over currently active network connections.%>
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/dmesg.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/dmesg.htm
deleted file mode 100644
index 1a8770ef88..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/dmesg.htm
+++ /dev/null
@@ -1,12 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-<%+header%>
-
<%:Kernel Log%>
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm
deleted file mode 100644
index 8820ae1cf3..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/index.htm
+++ /dev/null
@@ -1,487 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008-2011 Jo-Philipp Wich
- 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_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_nets = ntm:get_wan_networks()
- local wan6_nets = ntm:get_wan6_networks()
-
- 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_nets > 0 then
- local k, v
-
- rv.wan = { }
-
- for k, v in pairs(wan_nets) do
- local dev = v:get_interface()
- local link = dev and ipc.link(dev:name())
-
- local wan_info = {
- ipaddr = v:ipaddr(),
- gwaddr = v:gwaddr(),
- netmask = v:netmask(),
- dns = v:dnsaddrs(),
- expires = v:expires(),
- uptime = v:uptime(),
- proto = v:proto(),
- i18n = v:get_i18n(),
- ifname = v:ifname(),
- link = v:adminlink(),
- mac = dev and dev:mac(),
- type = dev and dev:type(),
- name = dev and dev:get_i18n(),
- ether = link and link.type == 1
- }
-
- rv.wan[#rv.wan+1] = wan_info
- end
- end
-
- if #wan6_nets > 0 then
- local k, v
-
- rv.wan6 = { }
-
- for k, v in pairs(wan6_nets) do
- local dev = v:get_interface()
- local link = dev and ipc.link(dev:name())
- local wan6_info = {
- ip6addr = v:ip6addr(),
- gw6addr = v:gw6addr(),
- dns = v:dns6addrs(),
- ip6prefix = v:ip6prefix(),
- uptime = v:uptime(),
- proto = v:proto(),
- i18n = v:get_i18n(),
- ifname = v:ifname(),
- link = v:adminlink(),
- mac = dev and dev:mac(),
- type = dev and dev:type(),
- name = dev and dev:get_i18n(),
- ether = link and link.type == 1
- }
-
- rv.wan6[#rv.wan6+1] = wan6_info
- end
- 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%>
-
-
-
-
-
-<%
- if has_dhcp then
- include("admin_network/lease_status")
- end
-%>
-
-<% if has_dsl then %>
-
-
<%:DSL%>
-
-
-
<%:Collecting data...%>
-
-
-<% end %>
-
-<% if has_wifi then %>
-
-
<%:Wireless%>
-
-
-
<%:Collecting data...%>
-
-
-
-
-
<%:Associated Stations%>
-
- <%+admin_network/wifi_assoclist%>
-
-<% 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%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/iptables.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/iptables.htm
deleted file mode 100644
index 51e428e40e..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/iptables.htm
+++ /dev/null
@@ -1,155 +0,0 @@
-<%#
- Copyright 2008-2009 Steven Barth
- Copyright 2008-2015 Jo-Philipp Wich
- 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 '%s' %{ 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 '%s' %{
- 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%>
-
-
-
-
-
- <% for _, tbl in ipairs(tables) do chaincnt = 0 %>
-
<%:Table%>: <%=tbl%>
-
- <% for _, chain in ipairs(ipt:chains(tbl)) do
- rowcnt = 0
- chaincnt = chaincnt + 1
- chaininfo = ipt:chain(tbl, chain)
- %>
-
- <%:Chain%> <%=chain%>
- (<%- if chaininfo.policy then -%>
- <%:Policy%>: <%=chaininfo.policy%>, <%:Packets%>: <%=chaininfo.packets%>, <%:Traffic%>: <%=wba.byte_format(chaininfo.bytes)-%>
- <%- else -%>
- <%:References%>: <%=chaininfo.references-%>
- <%- end -%>)
-
-
-
-
-
-
<%:Pkts.%>
-
<%:Traffic%>
-
<%:Target%>
-
<%:Prot.%>
-
<%:In%>
-
<%:Out%>
-
<%:Source%>
-
<%:Destination%>
-
<%:Options%>
-
-
- <% for _, rule in ipairs(ipt:find({table=tbl, chain=chain})) do %>
-
-
<%=rule.packets%>
-
<%=wba.byte_format(rule.bytes)%>
-
<%=rule.target and link_target(tbl, rule.target) or "-"%>
-
<%=rule.protocol%>
-
<%=link_iface(rule.inputif)%>
-
<%=link_iface(rule.outputif)%>
-
<%=rule.source%>
-
<%=rule.destination%>
-
<%=#rule.options > 0 and luci.util.pcdata(table.concat(rule.options, " ")) or "-"%>
-
- <% end %>
-
- <% if rowcnt == 1 then %>
-
-
<%:No rules in this chain%>
-
- <% end %>
-
-
- <% end %>
-
- <% if chaincnt == 0 then %>
- <%:No chains in this table%>
- <% end %>
-
-
- <% end %>
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/load.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/load.htm
deleted file mode 100644
index bced06fa22..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/load.htm
+++ /dev/null
@@ -1,285 +0,0 @@
-<%#
- Copyright 2010 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-<%+header%>
-
-
-
-
<%:Realtime Load%>
-
-
-
-
-
-
-
-
-
<%:1 Minute Load:%>
-
0
-
-
<%:Average:%>
-
0
-
-
<%:Peak:%>
-
0
-
-
-
<%:5 Minute Load:%>
-
0
-
-
<%:Average:%>
-
0
-
-
<%:Peak:%>
-
0
-
-
-
<%:15 Minute Load:%>
-
0
-
-
<%:Average:%>
-
0
-
-
<%:Peak:%>
-
0
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
deleted file mode 100644
index 74779f6ad8..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
+++ /dev/null
@@ -1,156 +0,0 @@
-<%#
- Copyright 2008-2009 Steven Barth
- Copyright 2008-2015 Jo-Philipp Wich
- 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%>
-
-
-
-
<%:Routes%>
-
<%:The following rules are currently active on this system.%>
-
-
-
-
-
-
-
<%_IPv4-Address%>
-
<%_MAC-Address%>
-
<%:Interface%>
-
-
- <%
- for _, v in ipairs(ip.neighbors({ family = 4 })) do
- if v.mac then
- %>
-
-
<%=v.dest%>
-
<%=v.mac%>
-
<%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%>
-
- <%
- style = not style
- end
- end
- %>
-
-
-
-
-
-
-
-
-
-
<%:Network%>
-
<%:Target%>
-
<%_IPv4-Gateway%>
-
<%:Metric%>
-
<%:Table%>
-
- <% for _, v in ipairs(ip.routes({ family = 4, type = 1 })) do %>
-
-
<%=luci.tools.webadmin.iface_get_network(v.dev) or v.dev%>
-
<%=v.dest%>
-
<%=v.gw or "-"%>
-
<%=v.metric or 0%>
-
<%=rtn[v.table] or v.table%>
-
- <% style = not style end %>
-
-
-
-
- <%
- if nixio.fs.access("/proc/net/ipv6_route") then
- style = true
- %>
-
-
-
-
-
-
<%:Network%>
-
<%:Target%>
-
<%:Source%>
-
<%:Metric%>
-
<%:Table%>
-
- <%
- for _, v in ipairs(ip.routes({ family = 6, type = 1 })) do
- if v.dest and not v.dest:is6linklocal() then
- %>
-
-
<%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%>
-
<%=v.dest%>
-
<%=v.from%>
-
<%=v.metric or 0%>
-
<%=rtn[v.table] or v.table%>
-
- <%
- style = not style
- end
- end
- %>
-
-
-
-
-
-
-
-
-
-
<%:IPv6-Address%>
-
<%:MAC-Address%>
-
<%:Interface%>
-
- <%
- for _, v in ipairs(ip.neighbors({ family = 6 })) do
- if v.dest and not v.dest:is6linklocal() and v.mac then
- %>
-
-
<%=v.dest%>
-
<%=v.mac%>
-
<%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%>
-
- <%
- style = not style
- end
- end
- %>
-
-
-
- <% end %>
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/syslog.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/syslog.htm
deleted file mode 100644
index fb734a76d9..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/syslog.htm
+++ /dev/null
@@ -1,12 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-<%+header%>
-
<%:System Log%>
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/wireless.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/wireless.htm
deleted file mode 100644
index 8ec43cb0e6..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/wireless.htm
+++ /dev/null
@@ -1,371 +0,0 @@
-<%#
- Copyright 2011 Jo-Philipp Wich
- 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%>
-
-
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/applyreboot.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/applyreboot.htm
deleted file mode 100644
index e235bd4679..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/applyreboot.htm
+++ /dev/null
@@ -1,53 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-
-
- <%=luci.sys.hostname()%> - <%= title or translate("Rebooting...") %>
-
-
-
-
-
-
-
-
-
<%=luci.sys.hostname() or "?"%>
-
-
-
-
-
-
-
-
<%:System%> - <%= title or translate("Rebooting...") %>
-
-
- <%= msg or translate("Changes applied.") %>
-
-
-
- <%:Waiting for changes to be applied...%>
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/backupfiles.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/backupfiles.htm
deleted file mode 100644
index c1f3361ae2..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/backupfiles.htm
+++ /dev/null
@@ -1,10 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-
<%:Click "Generate archive" to download a tar archive of the current configuration files.%>
-
-
-
-
-
<%:Restore%>
-
<%: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).%>
-
- <% if reset_avail then %>
-
- <% end %>
-
- <% if backup_invalid then %>
-
<%:The backup archive does not appear to be a valid gzip file.%>
- <% end %>
-
-
- <% local mtds = require("luci.sys").mtds(); if #mtds > 0 then -%>
-
<%:Save mtdblock contents%>
-
<%:Click "Save mtdblock" to download specified mtdblock file. (NOTE: THIS FEATURE IS FOR PROFESSIONALS! )%>
-
-
-
- <% end %>
-
-
-
-
-
<%:Flash new firmware image%>
- <% if upgrade_avail then %>
-
- <% else %>
-
<%: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.%>
- <% end %>
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/ipkg.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/ipkg.htm
deleted file mode 100644
index a7ff4e50bd..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/ipkg.htm
+++ /dev/null
@@ -1,10 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-
- <% local empty = true; opkg_list(querypat or letterpat, function(n, v, s, d) if filter[n] then return end; empty = false %>
-
-
<%=luci.util.pcdata(n)%>
-
<%=luci.util.pcdata(v)%>
-
<%=luci.util.pcdata(s)%>
-
<%=luci.util.pcdata(d)%>
-
-
-
-
- <% end) %>
- <% if empty then %>
-
-
-
<%:none%>
-
<%:none%>
-
<%:none%>
-
<%:none%>
-
- <% end %>
-
-
-
- <% end %>
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/reboot.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/reboot.htm
deleted file mode 100644
index d23664adac..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/reboot.htm
+++ /dev/null
@@ -1,62 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008-2015 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-<%+header%>
-
-
<%:Reboot%>
-
-
<%:Reboots the operating system of your device%>
-
-<%- local c = require("luci.model.uci").cursor():changes(); if c and next(c) then -%>
-
<%:Warning: There are unsaved changes that will get lost on reboot!%>
-<%- end -%>
-
-
-
-
-
-
-
- <%:Device is rebooting...%>
-
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/upgrade.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/upgrade.htm
deleted file mode 100644
index 597ddfd6bf..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/upgrade.htm
+++ /dev/null
@@ -1,65 +0,0 @@
-<%#
- Copyright 2008 Steven Barth
- Copyright 2008-2009 Jo-Philipp Wich
- Licensed to the public under the Apache License 2.0.
--%>
-
-<%+header%>
-
-
<%:Flash Firmware%> - <%:Verify%>
-
- <%_ The flash image was uploaded.
- Below is the checksum and file size listed,
- compare them with the original file to ensure data integrity.
- Click "Proceed" below to start the flash procedure. %>
-
- <% if storage > 0 and size > storage then %>
-
-
<%:It appears that you are trying to
- flash an image that does not fit into the flash memory, please verify
- the image file! %>
<%: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
- %>
-
<% if keep then %>
- <%:Configuration files will be kept%>
- <% else %>
- <%:Caution: Configuration files will be erased%>
- <% end %>
- <% if force then %>
-
- <%:Caution: System upgrade will be forced%>
-
- <% end %>
-
-
-
-
-
-
-
-<%+footer%>
diff --git a/modules/luci-mod-admin-full/luasrc/view/cbi/wireless_modefreq.htm b/modules/luci-mod-admin-full/luasrc/view/cbi/wireless_modefreq.htm
deleted file mode 100644
index ebb02e489b..0000000000
--- a/modules/luci-mod-admin-full/luasrc/view/cbi/wireless_modefreq.htm
+++ /dev/null
@@ -1,168 +0,0 @@
-<%+cbi/valueheader%>
-
-
-
-
-
-
-
-
-
-
-
-<%+cbi/valuefooter%>
diff --git a/modules/luci-mod-admin-full/root/etc/uci-defaults/50_luci-mod-admin-full b/modules/luci-mod-admin-full/root/etc/uci-defaults/50_luci-mod-admin-full
deleted file mode 100755
index 372eb15122..0000000000
--- a/modules/luci-mod-admin-full/root/etc/uci-defaults/50_luci-mod-admin-full
+++ /dev/null
@@ -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='${host:-openwrt.org}'
- set luci.diag.ping='${host:-openwrt.org}'
- set luci.diag.route='${host:-openwrt.org}'
- commit luci
- EOF
-fi
-
-exit 0
diff --git a/modules/luci-mod-admin-full/src/Makefile b/modules/luci-mod-admin-full/src/Makefile
deleted file mode 100644
index d6ed8c6e46..0000000000
--- a/modules/luci-mod-admin-full/src/Makefile
+++ /dev/null
@@ -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
diff --git a/modules/luci-mod-admin-full/src/luci-bwc.c b/modules/luci-mod-admin-full/src/luci-bwc.c
deleted file mode 100644
index 8ddd91727a..0000000000
--- a/modules/luci-mod-admin-full/src/luci-bwc.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- * luci-bwc - Very simple bandwidth collector cache for LuCI realtime graphs
- *
- * Copyright (C) 2010 Jo-Philipp Wich
- *
- * 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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-
-#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;
-}
diff --git a/modules/luci-mod-network/Makefile b/modules/luci-mod-network/Makefile
new file mode 100644
index 0000000000..5958765da7
--- /dev/null
+++ b/modules/luci-mod-network/Makefile
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2008-2014 The LuCI Team
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI Network Administration
+LUCI_DEPENDS:=+luci-base +libiwinfo-lua
+
+PKG_LICENSE:=Apache-2.0
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
+
diff --git a/modules/luci-mod-network/luasrc/controller/admin/network.lua b/modules/luci-mod-network/luasrc/controller/admin/network.lua
new file mode 100644
index 0000000000..a587b7e513
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/controller/admin/network.lua
@@ -0,0 +1,417 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2011-2018 Jo-Philipp Wich
+-- 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
+
+-- 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_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 = 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
+-- 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
+
+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 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 % luci.util.shellquote(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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/dhcp.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/dhcp.lua
new file mode 100644
index 0000000000..3ac49d635d
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/dhcp.lua
@@ -0,0 +1,346 @@
+-- Copyright 2008 Steven Barth
+-- 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 DHCP-Server and DNS-" ..
+ "Forwarder for NAT " ..
+ "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 DNS-Requests without " ..
+ "DNS-Name"))
+
+s:taboption("general", Flag, "authoritative",
+ translate("Authoritative"),
+ translate("This is the only DHCP" ..
+ "abbr> in the local network"))
+
+
+s:taboption("files", Flag, "readethers",
+ translate("Use /etc/ethers"),
+ translate("Read /etc/ethers to configure the DHCP-Server"))
+
+s:taboption("files", Value, "leasefile",
+ translate("Leasefile"),
+ translate("file where given 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 DNS file"))
+
+rf:depends("noresolv", "")
+rf.optional = true
+
+
+s:taboption("files", Flag, "nohosts",
+ translate("Ignore /etc/hosts")).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 DNS servers."))
+
+s:taboption("advanced", Flag, "strictorder",
+ translate("Strict order"),
+ translate("DNS 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 DNS 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 DNS " ..
+ "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("DNS 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("DNS 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("Max. DHCP 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("Max. EDNS0 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("Max. 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 = "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.") .. " " ..
+ translate("Use the Add Button to add a new lease entry. The MAC-Address " ..
+ "identifies the host, the IPv4-Address specifies the fixed address to " ..
+ "use, and the Hostname is assigned as a symbolic name to the requesting host. " ..
+ "The optional Lease time 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("MAC-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("IPv4-Address"))
+ip.datatype = "or(ip4addr,'ignore')"
+
+time = s:option(Value, "leasetime", translate("Lease time"))
+time.rmempty = true
+
+duid = s:option(Value, "duid", translate("DUID"))
+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("IPv6-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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/hosts.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/hosts.lua
new file mode 100644
index 0000000000..46945af58b
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/hosts.lua
@@ -0,0 +1,31 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2010-2015 Jo-Philipp Wich
+-- 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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/iface_add.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/iface_add.lua
new file mode 100644
index 0000000000..ca66e9f365
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/iface_add.lua
@@ -0,0 +1,101 @@
+-- Copyright 2009-2010 Jo-Philipp Wich
+-- 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: A-Z, a-z, " ..
+ "0-9 and _"
+ ))
+
+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"))
+
+
+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
+
+
+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_floating() then
+ sifname:depends({ _bridge = "", _netproto = p:proto()})
+ mifname:depends({ _bridge = "1", _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)
+ 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 })
+ if net then
+ local ifn
+ for ifn in utl.imatch(
+ br 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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/ifaces.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/ifaces.lua
new file mode 100644
index 0000000000..8be354b448
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/ifaces.lua
@@ -0,0 +1,563 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2008-2011 Jo-Philipp Wich
+-- 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 VLAN notation INTERFACE.VLANNR (e.g.: eth0.1)."))
+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 = s[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
+
+
+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
+
+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")
+
+ stp = s:taboption("physical", Flag, "stp", translate("Enable STP"),
+ 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 IGMP snooping"),
+ translate("Enables IGMP snooping on this bridge"))
+ igmp:depends("type", "bridge")
+ igmp.rmempty = true
+end
+
+
+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 unspecified to remove the interface from the associated zone or fill out the create 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 DHCP 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 (2m)."))
+ ltime.rmempty = true
+ ltime.default = "12h"
+
+ local dd = s:taboption("advanced", Flag, "dynamicdhcp",
+ translate("Dynamic DHCP"),
+ 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("IPv4-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 \"6,192.168.2.1," ..
+ "192.168.2.2\" 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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/network.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/network.lua
new file mode 100644
index 0000000000..799386d29c
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/network.lua
@@ -0,0 +1,265 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2008 Jo-Philipp Wich
+-- 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"
+
+m = Map("network", translate("Interfaces"))
+m:chain("wireless")
+m:chain("firewall")
+m:chain("dhcp")
+m.pageaction = false
+
+
+local tpl_networks = tpl.Template(nil, [[
+
+
+ <%
+ 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()
+ %>
+
+
+
+
+ <%=net[1]:upper()%>
+
+
+
+ ?
+
+
+
+
+ <%:Collecting data...%>
+
+
+
+ />
+
+ <% if disabled then %>
+
+ />
+ <% else %>
+
+ />
+ <% end %>
+
+ '" title="<%:Edit this interface%>" value="<%:Edit%>" id="<%=net[1]%>-ifc-edit"<%=ifattr(dynamic, "disabled", "disabled")%> />
+
+
+ />
+
+
+
+ <% end %>
+
+
+
+ '" />
+
+]])
+
+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"
+if network:has_ipv6() then
+ local s = m:section(NamedSection, "globals", "globals", translate("Global network options"))
+ local o = s:option(Value, "ula_prefix", translate("IPv6 ULA-Prefix"))
+ o.datatype = "ip6addr"
+ o.rmempty = true
+ m.pageaction = true
+end
+
+
+return m
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/proto_ahcp.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/proto_ahcp.lua
new file mode 100644
index 0000000000..0818199a93
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/proto_ahcp.lua
@@ -0,0 +1,67 @@
+-- Copyright 2011 Jo-Philipp Wich
+-- 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")
+
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/routes.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/routes.lua
new file mode 100644
index 0000000000..1970f36a28
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/routes.lua
@@ -0,0 +1,102 @@
+-- Copyright 2008 Steven Barth
+-- 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-IP or Network"))
+t.datatype = "ip4addr"
+t.rmempty = false
+
+n = s:option(Value, "netmask", translate("IPv4-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("IPv4-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
+
+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("IPv6-Address or Network (CIDR)"))
+ t.datatype = "ip6addr"
+ t.rmempty = false
+
+ g = s:option(Value, "gateway", translate("IPv6-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
+
+ 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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/vlan.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/vlan.lua
new file mode 100644
index 0000000000..d79b3c4704
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/vlan.lua
@@ -0,0 +1,364 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2010-2011 Jo-Philipp Wich
+-- 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 VLANs in which computers can communicate directly with each other. VLANs 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 = section.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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua
new file mode 100644
index 0000000000..743efaa1e8
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua
@@ -0,0 +1,1101 @@
+-- Copyright 2008 Steven Barth
+-- Licensed to the public under the Apache License 2.0.
+
+local wa = require "luci.tools.webadmin"
+local nw = require "luci.model.network"
+local ut = require "luci.util"
+local nt = require "luci.sys".net
+local fs = require "nixio.fs"
+
+local acct_port, acct_secret, acct_server, anonymous_identity, ant1, ant2,
+ auth, auth_port, auth_secret, auth_server, bssid, cacert, cacert2,
+ cc, ch, cipher, clientcert, clientcert2, ea, eaptype, en, encr,
+ ft_protocol, ft_psk_generate_local, hidden, htmode, identity,
+ ieee80211r, ieee80211w, ifname, isolate, key_retries,
+ legacyrates, max_timeout, meshfwd, meshid, ml, mobility_domain, mode,
+ mp, nasid, network, password, pmk_r1_push, privkey, privkey2, privkeypwd,
+ privkeypwd2, r0_key_lifetime, r0kh, r1_key_holder, r1kh,
+ reassociation_deadline, retry_timeout, ssid, st, tp, wepkey, wepslot,
+ wmm, wpakey, wps, disassoc_low_ack, short_preamble, beacon_int, dtim_period
+
+arg[1] = arg[1] or ""
+
+m = Map("wireless", "",
+ translate("The Device Configuration section covers physical settings of the radio " ..
+ "hardware such as channel, transmit power or antenna selection which are shared among all " ..
+ "defined wireless networks (if the radio hardware is multi-SSID capable). Per network settings " ..
+ "like encryption or operation mode are grouped in the Interface Configuration."))
+
+m:chain("network")
+m:chain("firewall")
+m.redirect = luci.dispatcher.build_url("admin/network/wireless")
+
+nw.init(m.uci)
+
+local wnet = nw:get_wifinet(arg[1])
+local wdev = wnet and wnet:get_device()
+
+-- redirect to overview page if network does not exist anymore (e.g. after a revert)
+if not wnet or not wdev then
+ luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
+ return
+end
+
+local function txpower_list(iw)
+ local list = iw.txpwrlist or { }
+ local off = tonumber(iw.txpower_offset) or 0
+ local new = { }
+ local prev = -1
+ local _, val
+ for _, val in ipairs(list) do
+ local dbm = val.dbm + off
+ local mw = math.floor(10 ^ (dbm / 10))
+ if mw ~= prev then
+ prev = mw
+ new[#new+1] = {
+ display_dbm = dbm,
+ display_mw = mw,
+ driver_dbm = val.dbm,
+ driver_mw = val.mw
+ }
+ end
+ end
+ return new
+end
+
+local function txpower_current(pwr, list)
+ pwr = tonumber(pwr)
+ if pwr ~= nil then
+ local _, item
+ for _, item in ipairs(list) do
+ if item.driver_dbm >= pwr then
+ return item.driver_dbm
+ end
+ end
+ end
+ return pwr or ""
+end
+
+local iw = luci.sys.wifi.getiwinfo(arg[1])
+local hw_modes = iw.hwmodelist or { }
+local tx_power_list = txpower_list(iw)
+local tx_power_cur = txpower_current(wdev:get("txpower"), tx_power_list)
+
+-- wireless toggle was requested, commit and reload page
+function m.parse(map)
+ local new_cc = m:formvalue("cbid.wireless.%s.country" % wdev:name())
+ local old_cc = m:get(wdev:name(), "country")
+
+ if m:formvalue("cbid.wireless.%s.__toggle" % wdev:name()) then
+ if wdev:get("disabled") == "1" or wnet:get("disabled") == "1" then
+ wnet:set("disabled", nil)
+ else
+ wnet:set("disabled", "1")
+ end
+ wdev:set("disabled", nil)
+ m.apply_needed = true
+ m.redirect = nil
+ end
+
+ Map.parse(map)
+
+ if m:get(wdev:name(), "type") == "mac80211" and new_cc and new_cc ~= old_cc then
+ luci.sys.call("iw reg set %s" % ut.shellquote(new_cc))
+
+ local old_ch = tonumber(m:formvalue("cbid.wireless.%s._mode_freq.channel" % wdev:name()) or "")
+ if old_ch then
+ local _, c, new_ch
+ for _, c in ipairs(iw.freqlist) do
+ if c.channel > old_ch or (old_ch <= 14 and c.channel > 14) then
+ break
+ end
+ new_ch = c.channel
+ end
+ if new_ch ~= old_ch then
+ wdev:set("channel", new_ch)
+ m.message = translatef("Channel %d is not available in the %s regulatory domain and has been auto-adjusted to %d.",
+ old_ch, new_cc, new_ch)
+ end
+ end
+ end
+
+ if wdev:get("disabled") == "1" or wnet:get("disabled") == "1" then
+ en.title = translate("Wireless network is disabled")
+ en.inputtitle = translate("Enable")
+ en.inputstyle = "apply"
+ else
+ en.title = translate("Wireless network is enabled")
+ en.inputtitle = translate("Disable")
+ en.inputstyle = "reset"
+ end
+end
+
+m.title = luci.util.pcdata(wnet:get_i18n())
+
+s = m:section(NamedSection, wdev:name(), "wifi-device", translate("Device Configuration"))
+s.addremove = false
+
+s:tab("general", translate("General Setup"))
+s:tab("macfilter", translate("MAC-Filter"))
+s:tab("advanced", translate("Advanced Settings"))
+
+st = s:taboption("general", DummyValue, "__status", translate("Status"))
+st.template = "admin_network/wifi_status"
+st.ifname = arg[1]
+
+en = s:taboption("general", Button, "__toggle")
+
+local hwtype = wdev:get("type")
+
+-- NanoFoo
+local nsantenna = wdev:get("antenna")
+
+-- Check whether there are client interfaces on the same radio,
+-- if yes, lock the channel choice as these stations will dicatate the freq
+local found_sta = nil
+local _, net
+if wnet:mode() ~= "sta" then
+ for _, net in ipairs(wdev:get_wifinets()) do
+ if net:mode() == "sta" and net:get("disabled") ~= "1" then
+ if not found_sta then
+ found_sta = {}
+ found_sta.channel = net:channel()
+ found_sta.names = {}
+ end
+ found_sta.names[#found_sta.names+1] = net:shortname()
+ end
+ end
+end
+
+if found_sta then
+ ch = s:taboption("general", DummyValue, "choice", translate("Channel"))
+ ch.value = translatef("Locked to channel %s used by: %s",
+ found_sta.channel or "(auto)", table.concat(found_sta.names, ", "))
+else
+ ch = s:taboption("general", Value, "_mode_freq", ' '..translate("Operating frequency"))
+ ch.iwinfo = iw
+ ch.template = "cbi/wireless_modefreq"
+
+ function ch.cfgvalue(self, section)
+ return {
+ m:get(section, "hwmode") or "",
+ m:get(section, "channel") or "auto",
+ m:get(section, "htmode") or ""
+ }
+ end
+
+ function ch.formvalue(self, section)
+ return {
+ m:formvalue(self:cbid(section) .. ".band") or (hw_modes.g and "11g" or "11a"),
+ m:formvalue(self:cbid(section) .. ".channel") or "auto",
+ m:formvalue(self:cbid(section) .. ".htmode") or ""
+ }
+ end
+
+ function ch.write(self, section, value)
+ m:set(section, "hwmode", value[1])
+ m:set(section, "channel", value[2])
+ m:set(section, "htmode", value[3])
+ end
+end
+
+------------------- MAC80211 Device ------------------
+
+if hwtype == "mac80211" then
+ if #tx_power_list > 0 then
+ tp = s:taboption("general", ListValue,
+ "txpower", translate("Transmit Power"), "dBm")
+ tp.rmempty = true
+ tp.default = tx_power_cur
+ function tp.cfgvalue(...)
+ return txpower_current(Value.cfgvalue(...), tx_power_list)
+ end
+
+ tp:value("", translate("auto"))
+ for _, p in ipairs(tx_power_list) do
+ tp:value(p.driver_dbm, "%i dBm (%i mW)"
+ %{ p.display_dbm, p.display_mw })
+ end
+ end
+
+ local cl = iw and iw.countrylist
+ if cl and #cl > 0 then
+ cc = s:taboption("advanced", ListValue, "country", translate("Country Code"), translate("Use ISO/IEC 3166 alpha2 country codes."))
+ cc.default = tostring(iw and iw.country or "00")
+ for _, c in ipairs(cl) do
+ cc:value(c.alpha2, "%s - %s" %{ c.alpha2, c.name })
+ end
+ else
+ s:taboption("advanced", Value, "country", translate("Country Code"), translate("Use ISO/IEC 3166 alpha2 country codes."))
+ end
+
+ legacyrates = s:taboption("advanced", Flag, "legacy_rates", translate("Allow legacy 802.11b rates"))
+ legacyrates.rmempty = false
+ legacyrates.default = "1"
+
+ s:taboption("advanced", Value, "distance", translate("Distance Optimization"),
+ translate("Distance to farthest network member in meters."))
+
+ -- external antenna profiles
+ local eal = iw and iw.extant
+ if eal and #eal > 0 then
+ ea = s:taboption("advanced", ListValue, "extant", translate("Antenna Configuration"))
+ for _, eap in ipairs(eal) do
+ ea:value(eap.id, "%s (%s)" %{ eap.name, eap.description })
+ if eap.selected then
+ ea.default = eap.id
+ end
+ end
+ end
+
+ s:taboption("advanced", Value, "frag", translate("Fragmentation Threshold"))
+ s:taboption("advanced", Value, "rts", translate("RTS/CTS Threshold"))
+
+ s:taboption("advanced", Flag, "noscan", translate("Force 40MHz mode"),
+ translate("Always use 40MHz channels even if the secondary channel overlaps. Using this option does not comply with IEEE 802.11n-2009!")).optional = true
+
+ beacon_int = s:taboption("advanced", Value, "beacon_int", translate("Beacon Interval"))
+ beacon_int.optional = true
+ beacon_int.placeholder = 100
+ beacon_int.datatype = "range(15,65535)"
+end
+
+
+------------------- Broadcom Device ------------------
+
+if hwtype == "broadcom" then
+ tp = s:taboption("general",
+ (#tx_power_list > 0) and ListValue or Value,
+ "txpower", translate("Transmit Power"), "dBm")
+
+ tp.rmempty = true
+ tp.default = tx_power_cur
+
+ function tp.cfgvalue(...)
+ return txpower_current(Value.cfgvalue(...), tx_power_list)
+ end
+
+ tp:value("", translate("auto"))
+ for _, p in ipairs(tx_power_list) do
+ tp:value(p.driver_dbm, "%i dBm (%i mW)"
+ %{ p.display_dbm, p.display_mw })
+ end
+
+ mode = s:taboption("advanced", ListValue, "hwmode", translate("Band"))
+ if hw_modes.b then
+ mode:value("11b", "2.4GHz (802.11b)")
+ if hw_modes.g then
+ mode:value("11bg", "2.4GHz (802.11b+g)")
+ end
+ end
+ if hw_modes.g then
+ mode:value("11g", "2.4GHz (802.11g)")
+ mode:value("11gst", "2.4GHz (802.11g + Turbo)")
+ mode:value("11lrs", "2.4GHz (802.11g Limited Rate Support)")
+ end
+ if hw_modes.a then mode:value("11a", "5GHz (802.11a)") end
+ if hw_modes.n then
+ if hw_modes.g then
+ mode:value("11ng", "2.4GHz (802.11g+n)")
+ mode:value("11n", "2.4GHz (802.11n)")
+ end
+ if hw_modes.a then
+ mode:value("11na", "5GHz (802.11a+n)")
+ mode:value("11n", "5GHz (802.11n)")
+ end
+ htmode = s:taboption("advanced", ListValue, "htmode", translate("HT mode (802.11n)"))
+ htmode:depends("hwmode", "11ng")
+ htmode:depends("hwmode", "11na")
+ htmode:depends("hwmode", "11n")
+ htmode:value("HT20", "20MHz")
+ htmode:value("HT40", "40MHz")
+ end
+
+ ant1 = s:taboption("advanced", ListValue, "txantenna", translate("Transmitter Antenna"))
+ ant1.widget = "radio"
+ ant1:depends("diversity", "")
+ ant1:value("3", translate("auto"))
+ ant1:value("0", translate("Antenna 1"))
+ ant1:value("1", translate("Antenna 2"))
+
+ ant2 = s:taboption("advanced", ListValue, "rxantenna", translate("Receiver Antenna"))
+ ant2.widget = "radio"
+ ant2:depends("diversity", "")
+ ant2:value("3", translate("auto"))
+ ant2:value("0", translate("Antenna 1"))
+ ant2:value("1", translate("Antenna 2"))
+
+ s:taboption("advanced", Flag, "frameburst", translate("Frame Bursting"))
+
+ s:taboption("advanced", Value, "distance", translate("Distance Optimization"))
+ --s:option(Value, "slottime", translate("Slot time"))
+
+ s:taboption("advanced", Value, "country", translate("Country Code"))
+ s:taboption("advanced", Value, "maxassoc", translate("Connection Limit"))
+end
+
+
+--------------------- HostAP Device ---------------------
+
+if hwtype == "prism2" then
+ s:taboption("advanced", Value, "txpower", translate("Transmit Power"), "att units").rmempty = true
+
+ s:taboption("advanced", Flag, "diversity", translate("Diversity")).rmempty = false
+
+ s:taboption("advanced", Value, "txantenna", translate("Transmitter Antenna"))
+ s:taboption("advanced", Value, "rxantenna", translate("Receiver Antenna"))
+end
+
+
+----------------------- Interface -----------------------
+
+s = m:section(NamedSection, wnet.sid, "wifi-iface", translate("Interface Configuration"))
+s.addremove = false
+s.anonymous = true
+s.defaults.device = wdev:name()
+
+s:tab("general", translate("General Setup"))
+s:tab("encryption", translate("Wireless Security"))
+s:tab("macfilter", translate("MAC-Filter"))
+s:tab("advanced", translate("Advanced Settings"))
+
+mode = s:taboption("general", ListValue, "mode", translate("Mode"))
+mode.override_values = true
+mode:value("ap", translate("Access Point"))
+mode:value("sta", translate("Client"))
+mode:value("adhoc", translate("Ad-Hoc"))
+
+meshid = s:taboption("general", Value, "mesh_id", translate("Mesh Id"))
+meshid:depends({mode="mesh"})
+
+meshfwd = s:taboption("advanced", Flag, "mesh_fwding", translate("Forward mesh peer traffic"))
+meshfwd.rmempty = false
+meshfwd.default = "1"
+meshfwd:depends({mode="mesh"})
+
+ssid = s:taboption("general", Value, "ssid", translate("ESSID"))
+ssid.datatype = "maxlength(32)"
+ssid:depends({mode="ap"})
+ssid:depends({mode="sta"})
+ssid:depends({mode="adhoc"})
+ssid:depends({mode="ahdemo"})
+ssid:depends({mode="monitor"})
+ssid:depends({mode="ap-wds"})
+ssid:depends({mode="sta-wds"})
+ssid:depends({mode="wds"})
+
+bssid = s:taboption("general", Value, "bssid", translate("BSSID"))
+
+network = s:taboption("general", Value, "network", translate("Network"),
+ translate("Choose the network(s) you want to attach to this wireless interface or " ..
+ "fill out the create field to define a new network."))
+
+network.rmempty = true
+network.template = "cbi/network_netlist"
+network.widget = "checkbox"
+network.novirtual = true
+
+function network.write(self, section, value)
+ local i = nw:get_interface(section)
+ if i then
+ local _, net, old, new = nil, nil, {}, {}
+
+ for _, net in ipairs(i:get_networks()) do
+ old[net:name()] = true
+ end
+
+ for net in ut.imatch(value) do
+ new[net] = true
+ if not old[net] then
+ local n = nw:get_network(net) or nw:add_network(net, { proto = "none" })
+ if n then
+ if not n:is_empty() then
+ n:set("type", "bridge")
+ end
+ n:add_interface(i)
+ end
+ end
+ end
+
+ for net, _ in pairs(old) do
+ if not new[net] then
+ local n = nw:get_network(net)
+ if n then
+ n:del_interface(i)
+ end
+ end
+ end
+ end
+end
+
+-------------------- MAC80211 Interface ----------------------
+
+if hwtype == "mac80211" then
+ if fs.access("/usr/sbin/iw") then
+ mode:value("mesh", "802.11s")
+ end
+
+ mode:value("ahdemo", translate("Pseudo Ad-Hoc (ahdemo)"))
+ mode:value("monitor", translate("Monitor"))
+ bssid:depends({mode="adhoc"})
+ bssid:depends({mode="sta"})
+ bssid:depends({mode="sta-wds"})
+
+ mp = s:taboption("macfilter", ListValue, "macfilter", translate("MAC-Address Filter"))
+ mp:depends({mode="ap"})
+ mp:depends({mode="ap-wds"})
+ mp:value("", translate("disable"))
+ mp:value("allow", translate("Allow listed only"))
+ mp:value("deny", translate("Allow all except listed"))
+
+ ml = s:taboption("macfilter", DynamicList, "maclist", translate("MAC-List"))
+ ml.datatype = "macaddr"
+ ml:depends({macfilter="allow"})
+ ml:depends({macfilter="deny"})
+ nt.mac_hints(function(mac, name) ml:value(mac, "%s (%s)" %{ mac, name }) end)
+
+ mode:value("ap-wds", "%s (%s)" % {translate("Access Point"), translate("WDS")})
+ mode:value("sta-wds", "%s (%s)" % {translate("Client"), translate("WDS")})
+
+ function mode.write(self, section, value)
+ if value == "ap-wds" then
+ ListValue.write(self, section, "ap")
+ m.uci:set("wireless", section, "wds", 1)
+ elseif value == "sta-wds" then
+ ListValue.write(self, section, "sta")
+ m.uci:set("wireless", section, "wds", 1)
+ else
+ ListValue.write(self, section, value)
+ m.uci:delete("wireless", section, "wds")
+ end
+ end
+
+ function mode.cfgvalue(self, section)
+ local mode = ListValue.cfgvalue(self, section)
+ local wds = m.uci:get("wireless", section, "wds") == "1"
+
+ if mode == "ap" and wds then
+ return "ap-wds"
+ elseif mode == "sta" and wds then
+ return "sta-wds"
+ else
+ return mode
+ end
+ end
+
+ hidden = s:taboption("general", Flag, "hidden", translate("Hide ESSID"))
+ hidden:depends({mode="ap"})
+ hidden:depends({mode="ap-wds"})
+
+ wmm = s:taboption("general", Flag, "wmm", translate("WMM Mode"))
+ wmm:depends({mode="ap"})
+ wmm:depends({mode="ap-wds"})
+ wmm.default = wmm.enabled
+
+ isolate = s:taboption("advanced", Flag, "isolate", translate("Isolate Clients"),
+ translate("Prevents client-to-client communication"))
+ isolate:depends({mode="ap"})
+ isolate:depends({mode="ap-wds"})
+
+ ifname = s:taboption("advanced", Value, "ifname", translate("Interface name"), translate("Override default interface name"))
+ ifname.optional = true
+
+ short_preamble = s:taboption("advanced", Flag, "short_preamble", translate("Short Preamble"))
+ short_preamble.default = short_preamble.enabled
+
+ dtim_period = s:taboption("advanced", Value, "dtim_period", translate("DTIM Interval"), translate("Delivery Traffic Indication Message Interval"))
+ dtim_period.optional = true
+ dtim_period.placeholder = 2
+ dtim_period.datatype = "range(1,255)"
+
+ disassoc_low_ack = s:taboption("advanced", Flag, "disassoc_low_ack", translate("Disassociate On Low Acknowledgement"),
+ translate("Allow AP mode to disconnect STAs based on low ACK condition"))
+ disassoc_low_ack.default = disassoc_low_ack.enabled
+end
+
+
+-------------------- Broadcom Interface ----------------------
+
+if hwtype == "broadcom" then
+ mode:value("wds", translate("WDS"))
+ mode:value("monitor", translate("Monitor"))
+
+ hidden = s:taboption("general", Flag, "hidden", translate("Hide ESSID"))
+ hidden:depends({mode="ap"})
+ hidden:depends({mode="adhoc"})
+ hidden:depends({mode="wds"})
+
+ isolate = s:taboption("advanced", Flag, "isolate", translate("Separate Clients"),
+ translate("Prevents client-to-client communication"))
+ isolate:depends({mode="ap"})
+
+ s:taboption("advanced", Flag, "doth", "802.11h")
+ s:taboption("advanced", Flag, "wmm", translate("WMM Mode"))
+
+ bssid:depends({mode="wds"})
+ bssid:depends({mode="adhoc"})
+end
+
+
+----------------------- HostAP Interface ---------------------
+
+if hwtype == "prism2" then
+ mode:value("wds", translate("WDS"))
+ mode:value("monitor", translate("Monitor"))
+
+ hidden = s:taboption("general", Flag, "hidden", translate("Hide ESSID"))
+ hidden:depends({mode="ap"})
+ hidden:depends({mode="adhoc"})
+ hidden:depends({mode="wds"})
+
+ bssid:depends({mode="sta"})
+
+ mp = s:taboption("macfilter", ListValue, "macpolicy", translate("MAC-Address Filter"))
+ mp:value("", translate("disable"))
+ mp:value("allow", translate("Allow listed only"))
+ mp:value("deny", translate("Allow all except listed"))
+ ml = s:taboption("macfilter", DynamicList, "maclist", translate("MAC-List"))
+ ml:depends({macpolicy="allow"})
+ ml:depends({macpolicy="deny"})
+ nt.mac_hints(function(mac, name) ml:value(mac, "%s (%s)" %{ mac, name }) end)
+
+ s:taboption("advanced", Value, "rate", translate("Transmission Rate"))
+ s:taboption("advanced", Value, "frag", translate("Fragmentation Threshold"))
+ s:taboption("advanced", Value, "rts", translate("RTS/CTS Threshold"))
+end
+
+
+------------------- WiFI-Encryption -------------------
+
+encr = s:taboption("encryption", ListValue, "encryption", translate("Encryption"))
+encr.override_values = true
+encr.override_depends = true
+encr:depends({mode="ap"})
+encr:depends({mode="sta"})
+encr:depends({mode="adhoc"})
+encr:depends({mode="ahdemo"})
+encr:depends({mode="ap-wds"})
+encr:depends({mode="sta-wds"})
+encr:depends({mode="mesh"})
+
+cipher = s:taboption("encryption", ListValue, "cipher", translate("Cipher"))
+cipher:depends({encryption="wpa"})
+cipher:depends({encryption="wpa2"})
+cipher:depends({encryption="psk"})
+cipher:depends({encryption="psk2"})
+cipher:depends({encryption="wpa-mixed"})
+cipher:depends({encryption="psk-mixed"})
+cipher:value("auto", translate("auto"))
+cipher:value("ccmp", translate("Force CCMP (AES)"))
+cipher:value("tkip", translate("Force TKIP"))
+cipher:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)"))
+
+function encr.cfgvalue(self, section)
+ local v = tostring(ListValue.cfgvalue(self, section))
+ if v == "wep" then
+ return "wep-open"
+ elseif v and v:match("%+") then
+ return (v:gsub("%+.+$", ""))
+ end
+ return v
+end
+
+function encr.write(self, section, value)
+ local e = tostring(encr:formvalue(section))
+ local c = tostring(cipher:formvalue(section))
+ if value == "wpa" or value == "wpa2" then
+ self.map.uci:delete("wireless", section, "key")
+ end
+ if e and (c == "tkip" or c == "ccmp" or c == "tkip+ccmp") then
+ e = e .. "+" .. c
+ end
+ self.map:set(section, "encryption", e)
+end
+
+function cipher.cfgvalue(self, section)
+ local v = tostring(ListValue.cfgvalue(encr, section))
+ if v and v:match("%+") then
+ v = v:gsub("^[^%+]+%+", "")
+ if v == "aes" then v = "ccmp"
+ elseif v == "tkip+aes" then v = "tkip+ccmp"
+ elseif v == "aes+tkip" then v = "tkip+ccmp"
+ elseif v == "ccmp+tkip" then v = "tkip+ccmp"
+ end
+ end
+ return v
+end
+
+function cipher.write(self, section)
+ return encr:write(section)
+end
+
+
+encr:value("none", "No Encryption")
+encr:value("wep-open", translate("WEP Open System"), {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"}, {mode="ahdemo"}, {mode="wds"})
+encr:value("wep-shared", translate("WEP Shared Key"), {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"}, {mode="ahdemo"}, {mode="wds"})
+
+if hwtype == "mac80211" or hwtype == "prism2" then
+ local supplicant = fs.access("/usr/sbin/wpa_supplicant")
+ local hostapd = fs.access("/usr/sbin/hostapd")
+
+ -- Probe EAP support
+ local has_ap_eap = (os.execute("hostapd -veap >/dev/null 2>/dev/null") == 0)
+ local has_sta_eap = (os.execute("wpa_supplicant -veap >/dev/null 2>/dev/null") == 0)
+
+ if hostapd and supplicant then
+ encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"})
+ encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"})
+ encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"})
+ if has_ap_eap and has_sta_eap then
+ encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+ encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+ end
+ elseif hostapd and not supplicant then
+ encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="ap-wds"})
+ encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="ap-wds"})
+ encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="ap-wds"})
+ if has_ap_eap then
+ encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="ap-wds"})
+ encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="ap-wds"})
+ end
+ encr.description = translate(
+ "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
+ "and ad-hoc mode) to be installed."
+ )
+ elseif not hostapd and supplicant then
+ encr:value("psk", "WPA-PSK", {mode="sta"}, {mode="sta-wds"}, {mode="adhoc"})
+ encr:value("psk2", "WPA2-PSK", {mode="sta"}, {mode="sta-wds"}, {mode="adhoc"})
+ encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="sta"}, {mode="sta-wds"}, {mode="adhoc"})
+ if has_sta_eap then
+ encr:value("wpa", "WPA-EAP", {mode="sta"}, {mode="sta-wds"})
+ encr:value("wpa2", "WPA2-EAP", {mode="sta"}, {mode="sta-wds"})
+ end
+ encr.description = translate(
+ "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
+ "and ad-hoc mode) to be installed."
+ )
+ else
+ encr.description = translate(
+ "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
+ "and ad-hoc mode) to be installed."
+ )
+ end
+elseif hwtype == "broadcom" then
+ encr:value("psk", "WPA-PSK")
+ encr:value("psk2", "WPA2-PSK")
+ encr:value("psk+psk2", "WPA-PSK/WPA2-PSK Mixed Mode")
+end
+
+auth_server = s:taboption("encryption", Value, "auth_server", translate("Radius-Authentication-Server"))
+auth_server:depends({mode="ap", encryption="wpa"})
+auth_server:depends({mode="ap", encryption="wpa2"})
+auth_server:depends({mode="ap-wds", encryption="wpa"})
+auth_server:depends({mode="ap-wds", encryption="wpa2"})
+auth_server.rmempty = true
+auth_server.datatype = "host(0)"
+
+auth_port = s:taboption("encryption", Value, "auth_port", translate("Radius-Authentication-Port"), translatef("Default %d", 1812))
+auth_port:depends({mode="ap", encryption="wpa"})
+auth_port:depends({mode="ap", encryption="wpa2"})
+auth_port:depends({mode="ap-wds", encryption="wpa"})
+auth_port:depends({mode="ap-wds", encryption="wpa2"})
+auth_port.rmempty = true
+auth_port.datatype = "port"
+
+auth_secret = s:taboption("encryption", Value, "auth_secret", translate("Radius-Authentication-Secret"))
+auth_secret:depends({mode="ap", encryption="wpa"})
+auth_secret:depends({mode="ap", encryption="wpa2"})
+auth_secret:depends({mode="ap-wds", encryption="wpa"})
+auth_secret:depends({mode="ap-wds", encryption="wpa2"})
+auth_secret.rmempty = true
+auth_secret.password = true
+
+acct_server = s:taboption("encryption", Value, "acct_server", translate("Radius-Accounting-Server"))
+acct_server:depends({mode="ap", encryption="wpa"})
+acct_server:depends({mode="ap", encryption="wpa2"})
+acct_server:depends({mode="ap-wds", encryption="wpa"})
+acct_server:depends({mode="ap-wds", encryption="wpa2"})
+acct_server.rmempty = true
+acct_server.datatype = "host(0)"
+
+acct_port = s:taboption("encryption", Value, "acct_port", translate("Radius-Accounting-Port"), translatef("Default %d", 1813))
+acct_port:depends({mode="ap", encryption="wpa"})
+acct_port:depends({mode="ap", encryption="wpa2"})
+acct_port:depends({mode="ap-wds", encryption="wpa"})
+acct_port:depends({mode="ap-wds", encryption="wpa2"})
+acct_port.rmempty = true
+acct_port.datatype = "port"
+
+acct_secret = s:taboption("encryption", Value, "acct_secret", translate("Radius-Accounting-Secret"))
+acct_secret:depends({mode="ap", encryption="wpa"})
+acct_secret:depends({mode="ap", encryption="wpa2"})
+acct_secret:depends({mode="ap-wds", encryption="wpa"})
+acct_secret:depends({mode="ap-wds", encryption="wpa2"})
+acct_secret.rmempty = true
+acct_secret.password = true
+
+wpakey = s:taboption("encryption", Value, "_wpa_key", translate("Key"))
+wpakey:depends("encryption", "psk")
+wpakey:depends("encryption", "psk2")
+wpakey:depends("encryption", "psk+psk2")
+wpakey:depends("encryption", "psk-mixed")
+wpakey.datatype = "wpakey"
+wpakey.rmempty = true
+wpakey.password = true
+
+wpakey.cfgvalue = function(self, section, value)
+ local key = m.uci:get("wireless", section, "key")
+ if key == "1" or key == "2" or key == "3" or key == "4" then
+ return nil
+ end
+ return key
+end
+
+wpakey.write = function(self, section, value)
+ self.map.uci:set("wireless", section, "key", value)
+ self.map.uci:delete("wireless", section, "key1")
+end
+
+
+wepslot = s:taboption("encryption", ListValue, "_wep_key", translate("Used Key Slot"))
+wepslot:depends("encryption", "wep-open")
+wepslot:depends("encryption", "wep-shared")
+wepslot:value("1", translatef("Key #%d", 1))
+wepslot:value("2", translatef("Key #%d", 2))
+wepslot:value("3", translatef("Key #%d", 3))
+wepslot:value("4", translatef("Key #%d", 4))
+
+wepslot.cfgvalue = function(self, section)
+ local slot = tonumber(m.uci:get("wireless", section, "key"))
+ if not slot or slot < 1 or slot > 4 then
+ return 1
+ end
+ return slot
+end
+
+wepslot.write = function(self, section, value)
+ self.map.uci:set("wireless", section, "key", value)
+end
+
+local slot
+for slot=1,4 do
+ wepkey = s:taboption("encryption", Value, "key" .. slot, translatef("Key #%d", slot))
+ wepkey:depends("encryption", "wep-open")
+ wepkey:depends("encryption", "wep-shared")
+ wepkey.datatype = "wepkey"
+ wepkey.rmempty = true
+ wepkey.password = true
+
+ function wepkey.write(self, section, value)
+ if value and (#value == 5 or #value == 13) then
+ value = "s:" .. value
+ end
+ return Value.write(self, section, value)
+ end
+end
+
+
+if hwtype == "mac80211" or hwtype == "prism2" then
+
+ -- Probe 802.11r support (and EAP support as a proxy for Openwrt)
+ local has_80211r = (os.execute("hostapd -v11r 2>/dev/null || hostapd -veap 2>/dev/null") == 0)
+
+ ieee80211r = s:taboption("encryption", Flag, "ieee80211r",
+ translate("802.11r Fast Transition"),
+ translate("Enables fast roaming among access points that belong " ..
+ "to the same Mobility Domain"))
+ ieee80211r:depends({mode="ap", encryption="wpa"})
+ ieee80211r:depends({mode="ap", encryption="wpa2"})
+ ieee80211r:depends({mode="ap-wds", encryption="wpa"})
+ ieee80211r:depends({mode="ap-wds", encryption="wpa2"})
+ if has_80211r then
+ ieee80211r:depends({mode="ap", encryption="psk"})
+ ieee80211r:depends({mode="ap", encryption="psk2"})
+ ieee80211r:depends({mode="ap", encryption="psk-mixed"})
+ ieee80211r:depends({mode="ap-wds", encryption="psk"})
+ ieee80211r:depends({mode="ap-wds", encryption="psk2"})
+ ieee80211r:depends({mode="ap-wds", encryption="psk-mixed"})
+ end
+ ieee80211r.rmempty = true
+
+ nasid = s:taboption("encryption", Value, "nasid", translate("NAS ID"),
+ translate("Used for two different purposes: RADIUS NAS ID and " ..
+ "802.11r R0KH-ID. Not needed with normal WPA(2)-PSK."))
+ nasid:depends({mode="ap", encryption="wpa"})
+ nasid:depends({mode="ap", encryption="wpa2"})
+ nasid:depends({mode="ap-wds", encryption="wpa"})
+ nasid:depends({mode="ap-wds", encryption="wpa2"})
+ nasid:depends({ieee80211r="1"})
+ nasid.rmempty = true
+
+ mobility_domain = s:taboption("encryption", Value, "mobility_domain",
+ translate("Mobility Domain"),
+ translate("4-character hexadecimal ID"))
+ mobility_domain:depends({ieee80211r="1"})
+ mobility_domain.placeholder = "4f57"
+ mobility_domain.datatype = "and(hexstring,rangelength(4,4))"
+ mobility_domain.rmempty = true
+
+ reassociation_deadline = s:taboption("encryption", Value, "reassociation_deadline",
+ translate("Reassociation Deadline"),
+ translate("time units (TUs / 1.024 ms) [1000-65535]"))
+ reassociation_deadline:depends({ieee80211r="1"})
+ reassociation_deadline.placeholder = "1000"
+ reassociation_deadline.datatype = "range(1000,65535)"
+ reassociation_deadline.rmempty = true
+
+ ft_protocol = s:taboption("encryption", ListValue, "ft_over_ds", translate("FT protocol"))
+ ft_protocol:depends({ieee80211r="1"})
+ ft_protocol:value("1", translatef("FT over DS"))
+ ft_protocol:value("0", translatef("FT over the Air"))
+ ft_protocol.rmempty = true
+
+ ft_psk_generate_local = s:taboption("encryption", Flag, "ft_psk_generate_local",
+ translate("Generate PMK locally"),
+ translate("When using a PSK, the PMK can be generated locally without inter AP communications"))
+ ft_psk_generate_local:depends({ieee80211r="1"})
+
+ r0_key_lifetime = s:taboption("encryption", Value, "r0_key_lifetime",
+ translate("R0 Key Lifetime"), translate("minutes"))
+ r0_key_lifetime:depends({ieee80211r="1", ft_psk_generate_local=""})
+ r0_key_lifetime.placeholder = "10000"
+ r0_key_lifetime.datatype = "uinteger"
+ r0_key_lifetime.rmempty = true
+
+ r1_key_holder = s:taboption("encryption", Value, "r1_key_holder",
+ translate("R1 Key Holder"),
+ translate("6-octet identifier as a hex string - no colons"))
+ r1_key_holder:depends({ieee80211r="1", ft_psk_generate_local=""})
+ r1_key_holder.placeholder = "00004f577274"
+ r1_key_holder.datatype = "and(hexstring,rangelength(12,12))"
+ r1_key_holder.rmempty = true
+
+ pmk_r1_push = s:taboption("encryption", Flag, "pmk_r1_push", translate("PMK R1 Push"))
+ pmk_r1_push:depends({ieee80211r="1", ft_psk_generate_local=""})
+ pmk_r1_push.placeholder = "0"
+ pmk_r1_push.rmempty = true
+
+ r0kh = s:taboption("encryption", DynamicList, "r0kh", translate("External R0 Key Holder List"),
+ translate("List of R0KHs in the same Mobility Domain. " ..
+ " Format: MAC-address,NAS-Identifier,128-bit key as hex string. " ..
+ " This list is used to map R0KH-ID (NAS Identifier) to a destination " ..
+ "MAC address when requesting PMK-R1 key from the R0KH that the STA " ..
+ "used during the Initial Mobility Domain Association."))
+ r0kh:depends({ieee80211r="1", ft_psk_generate_local=""})
+ r0kh.rmempty = true
+
+ r1kh = s:taboption("encryption", DynamicList, "r1kh", translate("External R1 Key Holder List"),
+ translate ("List of R1KHs in the same Mobility Domain. "..
+ " Format: MAC-address,R1KH-ID as 6 octets with colons,128-bit key as hex string. "..
+ " This list is used to map R1KH-ID to a destination MAC address " ..
+ "when sending PMK-R1 key from the R0KH. This is also the " ..
+ "list of authorized R1KHs in the MD that can request PMK-R1 keys."))
+ r1kh:depends({ieee80211r="1", ft_psk_generate_local=""})
+ r1kh.rmempty = true
+ -- End of 802.11r options
+
+ eaptype = s:taboption("encryption", ListValue, "eap_type", translate("EAP-Method"))
+ eaptype:value("tls", "TLS")
+ eaptype:value("ttls", "TTLS")
+ eaptype:value("peap", "PEAP")
+ eaptype:value("fast", "FAST")
+ eaptype:depends({mode="sta", encryption="wpa"})
+ eaptype:depends({mode="sta", encryption="wpa2"})
+ eaptype:depends({mode="sta-wds", encryption="wpa"})
+ eaptype:depends({mode="sta-wds", encryption="wpa2"})
+
+ cacert = s:taboption("encryption", FileUpload, "ca_cert", translate("Path to CA-Certificate"))
+ cacert:depends({mode="sta", encryption="wpa"})
+ cacert:depends({mode="sta", encryption="wpa2"})
+ cacert:depends({mode="sta-wds", encryption="wpa"})
+ cacert:depends({mode="sta-wds", encryption="wpa2"})
+ cacert.rmempty = true
+
+ clientcert = s:taboption("encryption", FileUpload, "client_cert", translate("Path to Client-Certificate"))
+ clientcert:depends({mode="sta", eap_type="tls", encryption="wpa"})
+ clientcert:depends({mode="sta", eap_type="tls", encryption="wpa2"})
+ clientcert:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
+ clientcert:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
+
+ privkey = s:taboption("encryption", FileUpload, "priv_key", translate("Path to Private Key"))
+ privkey:depends({mode="sta", eap_type="tls", encryption="wpa2"})
+ privkey:depends({mode="sta", eap_type="tls", encryption="wpa"})
+ privkey:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
+ privkey:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
+
+ privkeypwd = s:taboption("encryption", Value, "priv_key_pwd", translate("Password of Private Key"))
+ privkeypwd:depends({mode="sta", eap_type="tls", encryption="wpa2"})
+ privkeypwd:depends({mode="sta", eap_type="tls", encryption="wpa"})
+ privkeypwd:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
+ privkeypwd:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
+ privkeypwd.rmempty = true
+ privkeypwd.password = true
+
+ auth = s:taboption("encryption", ListValue, "auth", translate("Authentication"))
+ auth:value("PAP", "PAP", {eap_type="ttls"})
+ auth:value("CHAP", "CHAP", {eap_type="ttls"})
+ auth:value("MSCHAP", "MSCHAP", {eap_type="ttls"})
+ auth:value("MSCHAPV2", "MSCHAPv2", {eap_type="ttls"})
+ auth:value("EAP-GTC")
+ auth:value("EAP-MD5")
+ auth:value("EAP-MSCHAPV2")
+ auth:value("EAP-TLS")
+ auth:depends({mode="sta", eap_type="fast", encryption="wpa2"})
+ auth:depends({mode="sta", eap_type="fast", encryption="wpa"})
+ auth:depends({mode="sta", eap_type="peap", encryption="wpa2"})
+ auth:depends({mode="sta", eap_type="peap", encryption="wpa"})
+ auth:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
+ auth:depends({mode="sta", eap_type="ttls", encryption="wpa"})
+ auth:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
+ auth:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
+ auth:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
+ auth:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
+ auth:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
+ auth:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
+
+ cacert2 = s:taboption("encryption", FileUpload, "ca_cert2", translate("Path to inner CA-Certificate"))
+ cacert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
+ cacert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
+ cacert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
+ cacert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
+
+ clientcert2 = s:taboption("encryption", FileUpload, "client_cert2", translate("Path to inner Client-Certificate"))
+ clientcert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
+ clientcert2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
+ clientcert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
+ clientcert2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
+
+ privkey2 = s:taboption("encryption", FileUpload, "priv_key2", translate("Path to inner Private Key"))
+ privkey2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
+ privkey2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
+ privkey2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
+ privkey2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
+
+ privkeypwd2 = s:taboption("encryption", Value, "priv_key2_pwd", translate("Password of inner Private Key"))
+ privkeypwd2:depends({mode="sta", auth="EAP-TLS", encryption="wpa"})
+ privkeypwd2:depends({mode="sta", auth="EAP-TLS", encryption="wpa2"})
+ privkeypwd2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa"})
+ privkeypwd2:depends({mode="sta-wds", auth="EAP-TLS", encryption="wpa2"})
+ privkeypwd2.rmempty = true
+ privkeypwd2.password = true
+
+ identity = s:taboption("encryption", Value, "identity", translate("Identity"))
+ identity:depends({mode="sta", eap_type="fast", encryption="wpa2"})
+ identity:depends({mode="sta", eap_type="fast", encryption="wpa"})
+ identity:depends({mode="sta", eap_type="peap", encryption="wpa2"})
+ identity:depends({mode="sta", eap_type="peap", encryption="wpa"})
+ identity:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
+ identity:depends({mode="sta", eap_type="ttls", encryption="wpa"})
+ identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
+ identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
+ identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
+ identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
+ identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
+ identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
+ identity:depends({mode="sta", eap_type="tls", encryption="wpa2"})
+ identity:depends({mode="sta", eap_type="tls", encryption="wpa"})
+ identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
+ identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
+
+ anonymous_identity = s:taboption("encryption", Value, "anonymous_identity", translate("Anonymous Identity"))
+ anonymous_identity:depends({mode="sta", eap_type="fast", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta", eap_type="fast", encryption="wpa"})
+ anonymous_identity:depends({mode="sta", eap_type="peap", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta", eap_type="peap", encryption="wpa"})
+ anonymous_identity:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta", eap_type="ttls", encryption="wpa"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
+ anonymous_identity:depends({mode="sta", eap_type="tls", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta", eap_type="tls", encryption="wpa"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa2"})
+ anonymous_identity:depends({mode="sta-wds", eap_type="tls", encryption="wpa"})
+
+ password = s:taboption("encryption", Value, "password", translate("Password"))
+ password:depends({mode="sta", eap_type="fast", encryption="wpa2"})
+ password:depends({mode="sta", eap_type="fast", encryption="wpa"})
+ password:depends({mode="sta", eap_type="peap", encryption="wpa2"})
+ password:depends({mode="sta", eap_type="peap", encryption="wpa"})
+ password:depends({mode="sta", eap_type="ttls", encryption="wpa2"})
+ password:depends({mode="sta", eap_type="ttls", encryption="wpa"})
+ password:depends({mode="sta-wds", eap_type="fast", encryption="wpa2"})
+ password:depends({mode="sta-wds", eap_type="fast", encryption="wpa"})
+ password:depends({mode="sta-wds", eap_type="peap", encryption="wpa2"})
+ password:depends({mode="sta-wds", eap_type="peap", encryption="wpa"})
+ password:depends({mode="sta-wds", eap_type="ttls", encryption="wpa2"})
+ password:depends({mode="sta-wds", eap_type="ttls", encryption="wpa"})
+ password.rmempty = true
+ password.password = true
+end
+
+-- ieee802.11w options
+if hwtype == "mac80211" then
+ local has_80211w = (os.execute("hostapd -v11w 2>/dev/null || hostapd -veap 2>/dev/null") == 0)
+ if has_80211w then
+ ieee80211w = s:taboption("encryption", ListValue, "ieee80211w",
+ translate("802.11w Management Frame Protection"),
+ translate("Requires the 'full' version of wpad/hostapd " ..
+ "and support from the wifi driver (as of Feb 2017: " ..
+ "ath9k and ath10k, in LEDE also mwlwifi and mt76)"))
+ ieee80211w.default = ""
+ ieee80211w.rmempty = true
+ ieee80211w:value("", translate("Disabled (default)"))
+ ieee80211w:value("1", translate("Optional"))
+ ieee80211w:value("2", translate("Required"))
+ ieee80211w:depends({mode="ap", encryption="wpa2"})
+ ieee80211w:depends({mode="ap-wds", encryption="wpa2"})
+ ieee80211w:depends({mode="ap", encryption="psk2"})
+ ieee80211w:depends({mode="ap", encryption="psk-mixed"})
+ ieee80211w:depends({mode="ap-wds", encryption="psk2"})
+ ieee80211w:depends({mode="ap-wds", encryption="psk-mixed"})
+
+ max_timeout = s:taboption("encryption", Value, "ieee80211w_max_timeout",
+ translate("802.11w maximum timeout"),
+ translate("802.11w Association SA Query maximum timeout"))
+ max_timeout:depends({ieee80211w="1"})
+ max_timeout:depends({ieee80211w="2"})
+ max_timeout.datatype = "uinteger"
+ max_timeout.placeholder = "1000"
+ max_timeout.rmempty = true
+
+ retry_timeout = s:taboption("encryption", Value, "ieee80211w_retry_timeout",
+ translate("802.11w retry timeout"),
+ translate("802.11w Association SA Query retry timeout"))
+ retry_timeout:depends({ieee80211w="1"})
+ retry_timeout:depends({ieee80211w="2"})
+ retry_timeout.datatype = "uinteger"
+ retry_timeout.placeholder = "201"
+ retry_timeout.rmempty = true
+ end
+
+ key_retries = s:taboption("encryption", Flag, "wpa_disable_eapol_key_retries",
+ translate("Enable key reinstallation (KRACK) countermeasures"),
+ translate("Complicates key reinstallation attacks on the client side by disabling retransmission of EAPOL-Key frames that are used to install keys. This workaround might cause interoperability issues and reduced robustness of key negotiation especially in environments with heavy traffic load."))
+
+ key_retries:depends({mode="ap", encryption="wpa2"})
+ key_retries:depends({mode="ap", encryption="psk2"})
+ key_retries:depends({mode="ap", encryption="psk-mixed"})
+ key_retries:depends({mode="ap-wds", encryption="wpa2"})
+ key_retries:depends({mode="ap-wds", encryption="psk2"})
+ key_retries:depends({mode="ap-wds", encryption="psk-mixed"})
+end
+
+if hwtype == "mac80211" or hwtype == "prism2" then
+ local wpasupplicant = fs.access("/usr/sbin/wpa_supplicant")
+ local hostcli = fs.access("/usr/sbin/hostapd_cli")
+ if hostcli and wpasupplicant then
+ wps = s:taboption("encryption", Flag, "wps_pushbutton", translate("Enable WPS pushbutton, requires WPA(2)-PSK"))
+ wps.enabled = "1"
+ wps.disabled = "0"
+ wps.rmempty = false
+ wps:depends("encryption", "psk")
+ wps:depends("encryption", "psk2")
+ wps:depends("encryption", "psk-mixed")
+ end
+end
+
+return m
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi_add.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi_add.lua
new file mode 100644
index 0000000000..e8a3058826
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi_add.lua
@@ -0,0 +1,168 @@
+-- Copyright 2009 Jo-Philipp Wich
+-- 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: A-Z, a-z, " ..
+ "0-9 and _"
+ ))
+
+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 unspecified to remove the interface from the associated zone or fill out the create 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
diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi_overview.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi_overview.lua
new file mode 100644
index 0000000000..3bffb3502c
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi_overview.lua
@@ -0,0 +1,223 @@
+-- Copyright 2018 Jo-Philipp Wich
+-- 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, [[
+
+
+
+
+
+ <%=dev:name()%>
+
+
+ <%=hw%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <% if #wnets > 0 then %>
+ <% for i, net in ipairs(wnets) do local disabled = (dev:get("disabled") == "1" or net:get("disabled") == "1") %>
+
+
+ .png" /> 0%
+
+
">
+ <%= disabled and translate("Wireless is disabled") or translate("Collecting data...") %>
+
+
+
+ <% if disabled then %>
+
+
+ <% else %>
+
+
+ <% end %>
+
+
+
+
+
+
+
+
+ <% end %>
+ <% else %>
+
+
+ <%:No network configured on this device%>
+
+
+ <% end %>
+
+
+
+]])
+
+
+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([[
+
+
<%:Package libiwinfo required!%>
+
<%_The libiwinfo-lua package is not installed. You must install this component for working wireless configuration!%>
+
+ ]])
+ 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([[
+
<%:Associated Stations%>
+ <%+wifi_assoclist%>
+ ]])
+end
+
+return m
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/diagnostics.htm b/modules/luci-mod-network/luasrc/view/admin_network/diagnostics.htm
new file mode 100644
index 0000000000..03dd5aab29
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/diagnostics.htm
@@ -0,0 +1,117 @@
+<%#
+ Copyright 2010 Jo-Philipp Wich
+ 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 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"
+%>
+
+
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/iface_overview_status.htm b/modules/luci-mod-network/luasrc/view/admin_network/iface_overview_status.htm
new file mode 100644
index 0000000000..7427154a04
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/iface_overview_status.htm
@@ -0,0 +1,183 @@
+<%#
+ Copyright 2010-2018 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/iface_status.htm b/modules/luci-mod-network/luasrc/view/admin_network/iface_status.htm
new file mode 100644
index 0000000000..34be35dd20
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/iface_status.htm
@@ -0,0 +1,66 @@
+<%+cbi/valueheader%>
+
+
+
+
+
+
+ <%:Collecting data...%>
+
+
+
+<%+cbi/valuefooter%>
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/switch_status.htm b/modules/luci-mod-network/luasrc/view/admin_network/switch_status.htm
new file mode 100644
index 0000000000..68f0bbc9d4
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/switch_status.htm
@@ -0,0 +1,62 @@
+
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/wifi_join.htm b/modules/luci-mod-network/luasrc/view/admin_network/wifi_join.htm
new file mode 100644
index 0000000000..987123642f
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/wifi_join.htm
@@ -0,0 +1,224 @@
+<%#
+ Copyright 2009-2015 Jo-Philipp Wich
+ 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%>
+
+
+
+
<%:Join Network: Wireless Scan%>
+
+
+
+
+
+
<%:Signal%>
+
<%:SSID%>
+
<%:Channel%>
+
<%:Mode%>
+
<%:BSSID%>
+
<%:Encryption%>
+
+
+
+
+
+
+ <%:Collecting data...%>
+
+
+
+
+
+
+
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/wifi_overview_status.htm b/modules/luci-mod-network/luasrc/view/admin_network/wifi_overview_status.htm
new file mode 100644
index 0000000000..9730bc2c92
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/wifi_overview_status.htm
@@ -0,0 +1,127 @@
+<%#
+ Copyright 2008-2009 Steven Barth
+ Copyright 2008-2018 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+
diff --git a/modules/luci-mod-network/luasrc/view/admin_network/wifi_status.htm b/modules/luci-mod-network/luasrc/view/admin_network/wifi_status.htm
new file mode 100644
index 0000000000..bfad3d0804
--- /dev/null
+++ b/modules/luci-mod-network/luasrc/view/admin_network/wifi_status.htm
@@ -0,0 +1,77 @@
+<%+cbi/valueheader%>
+
+
+
+
+
+
+
+
+ <%:Collecting data...%>
+
+
+
+<%+cbi/valuefooter%>
diff --git a/modules/luci-mod-network/root/etc/uci-defaults/50_luci-mod-admin-full b/modules/luci-mod-network/root/etc/uci-defaults/50_luci-mod-admin-full
new file mode 100755
index 0000000000..372eb15122
--- /dev/null
+++ b/modules/luci-mod-network/root/etc/uci-defaults/50_luci-mod-admin-full
@@ -0,0 +1,22 @@
+#!/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='${host:-openwrt.org}'
+ set luci.diag.ping='${host:-openwrt.org}'
+ set luci.diag.route='${host:-openwrt.org}'
+ commit luci
+ EOF
+fi
+
+exit 0
diff --git a/modules/luci-mod-status/Makefile b/modules/luci-mod-status/Makefile
new file mode 100644
index 0000000000..cf8c8ddf83
--- /dev/null
+++ b/modules/luci-mod-status/Makefile
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2008-2014 The LuCI Team
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI Status Pages
+LUCI_DEPENDS:=+luci-base +libiwinfo +libiwinfo-lua
+
+PKG_BUILD_DEPENDS:=iwinfo
+PKG_LICENSE:=Apache-2.0
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
+
diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/bandwidth.svg b/modules/luci-mod-status/htdocs/luci-static/resources/bandwidth.svg
new file mode 100644
index 0000000000..5a121b85c6
--- /dev/null
+++ b/modules/luci-mod-status/htdocs/luci-static/resources/bandwidth.svg
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/connections.svg b/modules/luci-mod-status/htdocs/luci-static/resources/connections.svg
new file mode 100644
index 0000000000..5794e79426
--- /dev/null
+++ b/modules/luci-mod-status/htdocs/luci-static/resources/connections.svg
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/load.svg b/modules/luci-mod-status/htdocs/luci-static/resources/load.svg
new file mode 100644
index 0000000000..716d37617f
--- /dev/null
+++ b/modules/luci-mod-status/htdocs/luci-static/resources/load.svg
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/wifirate.svg b/modules/luci-mod-status/htdocs/luci-static/resources/wifirate.svg
new file mode 100644
index 0000000000..e75ea614c9
--- /dev/null
+++ b/modules/luci-mod-status/htdocs/luci-static/resources/wifirate.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/wireless.svg b/modules/luci-mod-status/htdocs/luci-static/resources/wireless.svg
new file mode 100644
index 0000000000..00cc2a12f1
--- /dev/null
+++ b/modules/luci-mod-status/htdocs/luci-static/resources/wireless.svg
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/modules/luci-mod-status/luasrc/controller/admin/status.lua b/modules/luci-mod-status/luasrc/controller/admin/status.lua
new file mode 100644
index 0000000000..4f04cce545
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/controller/admin/status.lua
@@ -0,0 +1,153 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2011 Jo-Philipp Wich
+-- Licensed to the public under the Apache License 2.0.
+
+module("luci.controller.admin.status", package.seeall)
+
+function index()
+ 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
diff --git a/modules/luci-mod-status/luasrc/model/cbi/admin_status/processes.lua b/modules/luci-mod-status/luasrc/model/cbi/admin_status/processes.lua
new file mode 100644
index 0000000000..0a6e48fd8e
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/model/cbi/admin_status/processes.lua
@@ -0,0 +1,34 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2008 Jo-Philipp Wich
+-- 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
\ No newline at end of file
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/bandwidth.htm b/modules/luci-mod-status/luasrc/view/admin_status/bandwidth.htm
new file mode 100644
index 0000000000..3bb55f9054
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/bandwidth.htm
@@ -0,0 +1,305 @@
+<%#
+ Copyright 2010 Jo-Philipp Wich
+ 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%>
+
+
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/connections.htm b/modules/luci-mod-status/luasrc/view/admin_status/connections.htm
new file mode 100644
index 0000000000..0a0db3be78
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/connections.htm
@@ -0,0 +1,376 @@
+<%#
+ Copyright 2010 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
+
+
+
<%:Realtime Connections%>
+
+
<%:This page gives an overview over currently active network connections.%>
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/dmesg.htm b/modules/luci-mod-status/luasrc/view/admin_status/dmesg.htm
new file mode 100644
index 0000000000..1a8770ef88
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/dmesg.htm
@@ -0,0 +1,12 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
<%:Kernel Log%>
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/index.htm b/modules/luci-mod-status/luasrc/view/admin_status/index.htm
new file mode 100644
index 0000000000..3edfd92047
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/index.htm
@@ -0,0 +1,487 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008-2011 Jo-Philipp Wich
+ 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_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_nets = ntm:get_wan_networks()
+ local wan6_nets = ntm:get_wan6_networks()
+
+ 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_nets > 0 then
+ local k, v
+
+ rv.wan = { }
+
+ for k, v in pairs(wan_nets) do
+ local dev = v:get_interface()
+ local link = dev and ipc.link(dev:name())
+
+ local wan_info = {
+ ipaddr = v:ipaddr(),
+ gwaddr = v:gwaddr(),
+ netmask = v:netmask(),
+ dns = v:dnsaddrs(),
+ expires = v:expires(),
+ uptime = v:uptime(),
+ proto = v:proto(),
+ i18n = v:get_i18n(),
+ ifname = v:ifname(),
+ link = v:adminlink(),
+ mac = dev and dev:mac(),
+ type = dev and dev:type(),
+ name = dev and dev:get_i18n(),
+ ether = link and link.type == 1
+ }
+
+ rv.wan[#rv.wan+1] = wan_info
+ end
+ end
+
+ if #wan6_nets > 0 then
+ local k, v
+
+ rv.wan6 = { }
+
+ for k, v in pairs(wan6_nets) do
+ local dev = v:get_interface()
+ local link = dev and ipc.link(dev:name())
+ local wan6_info = {
+ ip6addr = v:ip6addr(),
+ gw6addr = v:gw6addr(),
+ dns = v:dns6addrs(),
+ ip6prefix = v:ip6prefix(),
+ uptime = v:uptime(),
+ proto = v:proto(),
+ i18n = v:get_i18n(),
+ ifname = v:ifname(),
+ link = v:adminlink(),
+ mac = dev and dev:mac(),
+ type = dev and dev:type(),
+ name = dev and dev:get_i18n(),
+ ether = link and link.type == 1
+ }
+
+ rv.wan6[#rv.wan6+1] = wan6_info
+ end
+ 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%>
+
+
+
+
+
+<%
+ if has_dhcp then
+ include("lease_status")
+ end
+%>
+
+<% if has_dsl then %>
+
+
<%:DSL%>
+
+
+
<%:Collecting data...%>
+
+
+<% end %>
+
+<% if has_wifi then %>
+
+
<%:Wireless%>
+
+
+
<%:Collecting data...%>
+
+
+
+
+
<%:Associated Stations%>
+
+ <%+wifi_assoclist%>
+
+<% 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%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/iptables.htm b/modules/luci-mod-status/luasrc/view/admin_status/iptables.htm
new file mode 100644
index 0000000000..51e428e40e
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/iptables.htm
@@ -0,0 +1,155 @@
+<%#
+ Copyright 2008-2009 Steven Barth
+ Copyright 2008-2015 Jo-Philipp Wich
+ 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 '%s' %{ 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 '%s' %{
+ 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%>
+
+
+
+
+
+ <% for _, tbl in ipairs(tables) do chaincnt = 0 %>
+
<%:Table%>: <%=tbl%>
+
+ <% for _, chain in ipairs(ipt:chains(tbl)) do
+ rowcnt = 0
+ chaincnt = chaincnt + 1
+ chaininfo = ipt:chain(tbl, chain)
+ %>
+
+ <%:Chain%> <%=chain%>
+ (<%- if chaininfo.policy then -%>
+ <%:Policy%>: <%=chaininfo.policy%>, <%:Packets%>: <%=chaininfo.packets%>, <%:Traffic%>: <%=wba.byte_format(chaininfo.bytes)-%>
+ <%- else -%>
+ <%:References%>: <%=chaininfo.references-%>
+ <%- end -%>)
+
+
+
+
+
+
<%:Pkts.%>
+
<%:Traffic%>
+
<%:Target%>
+
<%:Prot.%>
+
<%:In%>
+
<%:Out%>
+
<%:Source%>
+
<%:Destination%>
+
<%:Options%>
+
+
+ <% for _, rule in ipairs(ipt:find({table=tbl, chain=chain})) do %>
+
+
<%=rule.packets%>
+
<%=wba.byte_format(rule.bytes)%>
+
<%=rule.target and link_target(tbl, rule.target) or "-"%>
+
<%=rule.protocol%>
+
<%=link_iface(rule.inputif)%>
+
<%=link_iface(rule.outputif)%>
+
<%=rule.source%>
+
<%=rule.destination%>
+
<%=#rule.options > 0 and luci.util.pcdata(table.concat(rule.options, " ")) or "-"%>
+
+ <% end %>
+
+ <% if rowcnt == 1 then %>
+
+
<%:No rules in this chain%>
+
+ <% end %>
+
+
+ <% end %>
+
+ <% if chaincnt == 0 then %>
+ <%:No chains in this table%>
+ <% end %>
+
+
+ <% end %>
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/load.htm b/modules/luci-mod-status/luasrc/view/admin_status/load.htm
new file mode 100644
index 0000000000..bced06fa22
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/load.htm
@@ -0,0 +1,285 @@
+<%#
+ Copyright 2010 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
+
+
+
<%:Realtime Load%>
+
+
+
-
+
+
+
+
+
<%:1 Minute Load:%>
+
0
+
+
<%:Average:%>
+
0
+
+
<%:Peak:%>
+
0
+
+
+
<%:5 Minute Load:%>
+
0
+
+
<%:Average:%>
+
0
+
+
<%:Peak:%>
+
0
+
+
+
<%:15 Minute Load:%>
+
0
+
+
<%:Average:%>
+
0
+
+
<%:Peak:%>
+
0
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/routes.htm b/modules/luci-mod-status/luasrc/view/admin_status/routes.htm
new file mode 100644
index 0000000000..74779f6ad8
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/routes.htm
@@ -0,0 +1,156 @@
+<%#
+ Copyright 2008-2009 Steven Barth
+ Copyright 2008-2015 Jo-Philipp Wich
+ 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%>
+
+
+
+
<%:Routes%>
+
<%:The following rules are currently active on this system.%>
+
+
+
+
+
+
+
<%_IPv4-Address%>
+
<%_MAC-Address%>
+
<%:Interface%>
+
+
+ <%
+ for _, v in ipairs(ip.neighbors({ family = 4 })) do
+ if v.mac then
+ %>
+
+
<%=v.dest%>
+
<%=v.mac%>
+
<%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%>
+
+ <%
+ style = not style
+ end
+ end
+ %>
+
+
+
+
+
+
+
+
+
+
<%:Network%>
+
<%:Target%>
+
<%_IPv4-Gateway%>
+
<%:Metric%>
+
<%:Table%>
+
+ <% for _, v in ipairs(ip.routes({ family = 4, type = 1 })) do %>
+
+
<%=luci.tools.webadmin.iface_get_network(v.dev) or v.dev%>
+
<%=v.dest%>
+
<%=v.gw or "-"%>
+
<%=v.metric or 0%>
+
<%=rtn[v.table] or v.table%>
+
+ <% style = not style end %>
+
+
+
+
+ <%
+ if nixio.fs.access("/proc/net/ipv6_route") then
+ style = true
+ %>
+
+
+
+
+
+
<%:Network%>
+
<%:Target%>
+
<%:Source%>
+
<%:Metric%>
+
<%:Table%>
+
+ <%
+ for _, v in ipairs(ip.routes({ family = 6, type = 1 })) do
+ if v.dest and not v.dest:is6linklocal() then
+ %>
+
+
<%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%>
+
<%=v.dest%>
+
<%=v.from%>
+
<%=v.metric or 0%>
+
<%=rtn[v.table] or v.table%>
+
+ <%
+ style = not style
+ end
+ end
+ %>
+
+
+
+
+
+
+
+
+
+
<%:IPv6-Address%>
+
<%:MAC-Address%>
+
<%:Interface%>
+
+ <%
+ for _, v in ipairs(ip.neighbors({ family = 6 })) do
+ if v.dest and not v.dest:is6linklocal() and v.mac then
+ %>
+
+
<%=v.dest%>
+
<%=v.mac%>
+
<%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%>
+
+ <%
+ style = not style
+ end
+ end
+ %>
+
+
+
+ <% end %>
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/syslog.htm b/modules/luci-mod-status/luasrc/view/admin_status/syslog.htm
new file mode 100644
index 0000000000..fb734a76d9
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/syslog.htm
@@ -0,0 +1,12 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
<%:System Log%>
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-status/luasrc/view/admin_status/wireless.htm b/modules/luci-mod-status/luasrc/view/admin_status/wireless.htm
new file mode 100644
index 0000000000..8ec43cb0e6
--- /dev/null
+++ b/modules/luci-mod-status/luasrc/view/admin_status/wireless.htm
@@ -0,0 +1,371 @@
+<%#
+ Copyright 2011 Jo-Philipp Wich
+ 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%>
+
+
+
+
+]] %{
+ 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 (e.g. ext3)"))
+
+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
diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua
new file mode 100644
index 0000000000..82468d5fcc
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua
@@ -0,0 +1,54 @@
+-- Copyright 2010 Jo-Philipp Wich
+-- 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 (e.g. /dev/sda1)"))
+
+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
diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/ipkg.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/ipkg.lua
new file mode 100644
index 0000000000..7c6d7e1c66
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/ipkg.lua
@@ -0,0 +1,64 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2008-2011 Jo-Philipp Wich
+-- 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
diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/leds.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/leds.lua
new file mode 100644
index 0000000000..2ea044e16a
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/leds.lua
@@ -0,0 +1,158 @@
+-- Copyright 2008 Steven Barth
+-- Licensed to the public under the Apache License 2.0.
+
+m = Map("system", translate("LED Configuration"), translate("Customizes the behaviour of the device LEDs 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("LED 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
diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/startup.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/startup.lua
new file mode 100644
index 0000000000..9e19ac50a2
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/startup.lua
@@ -0,0 +1,97 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2010-2012 Jo-Philipp Wich
+-- Copyright 2010 Manuel Munz
+-- 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. Warning: If you disable essential init scripts like \"network\", your device might become inaccessible!"))
+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
diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/system.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/system.lua
new file mode 100644
index 0000000000..c7fdfcddba
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/system.lua
@@ -0,0 +1,224 @@
+-- Copyright 2008 Steven Barth
+-- Copyright 2011 Jo-Philipp Wich
+-- 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
diff --git a/modules/luci-mod-system/luasrc/view/admin_system/applyreboot.htm b/modules/luci-mod-system/luasrc/view/admin_system/applyreboot.htm
new file mode 100644
index 0000000000..e235bd4679
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/view/admin_system/applyreboot.htm
@@ -0,0 +1,53 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+
+
+ <%=luci.sys.hostname()%> - <%= title or translate("Rebooting...") %>
+
+
+
+
+
+
+
+
+
<%=luci.sys.hostname() or "?"%>
+
+
+
+
+
+
+
+
<%:System%> - <%= title or translate("Rebooting...") %>
+
+
+ <%= msg or translate("Changes applied.") %>
+
+
+
+ <%:Waiting for changes to be applied...%>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/luci-mod-system/luasrc/view/admin_system/backupfiles.htm b/modules/luci-mod-system/luasrc/view/admin_system/backupfiles.htm
new file mode 100644
index 0000000000..c1f3361ae2
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/view/admin_system/backupfiles.htm
@@ -0,0 +1,10 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+
<%:Click "Generate archive" to download a tar archive of the current configuration files.%>
+
+
+
+
+
<%:Restore%>
+
<%: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).%>
+
+ <% if reset_avail then %>
+
+ <% end %>
+
+ <% if backup_invalid then %>
+
<%:The backup archive does not appear to be a valid gzip file.%>
+ <% end %>
+
+
+ <% local mtds = require("luci.sys").mtds(); if #mtds > 0 then -%>
+
<%:Save mtdblock contents%>
+
<%:Click "Save mtdblock" to download specified mtdblock file. (NOTE: THIS FEATURE IS FOR PROFESSIONALS! )%>
+
+
+
+ <% end %>
+
+
+
+
+
<%:Flash new firmware image%>
+ <% if upgrade_avail then %>
+
+ <% else %>
+
<%: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.%>
+ <% end %>
+
+
+<%+footer%>
diff --git a/modules/luci-mod-system/luasrc/view/admin_system/ipkg.htm b/modules/luci-mod-system/luasrc/view/admin_system/ipkg.htm
new file mode 100644
index 0000000000..a7ff4e50bd
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/view/admin_system/ipkg.htm
@@ -0,0 +1,10 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+
+ <% local empty = true; opkg_list(querypat or letterpat, function(n, v, s, d) if filter[n] then return end; empty = false %>
+
+
<%=luci.util.pcdata(n)%>
+
<%=luci.util.pcdata(v)%>
+
<%=luci.util.pcdata(s)%>
+
<%=luci.util.pcdata(d)%>
+
+
+
+
+ <% end) %>
+ <% if empty then %>
+
+
+
<%:none%>
+
<%:none%>
+
<%:none%>
+
<%:none%>
+
+ <% end %>
+
+
+
+ <% end %>
+
+
+<%+footer%>
diff --git a/modules/luci-mod-system/luasrc/view/admin_system/reboot.htm b/modules/luci-mod-system/luasrc/view/admin_system/reboot.htm
new file mode 100644
index 0000000000..d23664adac
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/view/admin_system/reboot.htm
@@ -0,0 +1,62 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008-2015 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
+
<%:Reboot%>
+
+
<%:Reboots the operating system of your device%>
+
+<%- local c = require("luci.model.uci").cursor():changes(); if c and next(c) then -%>
+
<%:Warning: There are unsaved changes that will get lost on reboot!%>
+<%- end -%>
+
+
+
+
+
+
+
+ <%:Device is rebooting...%>
+
+
+
+
+<%+footer%>
diff --git a/modules/luci-mod-system/luasrc/view/admin_system/upgrade.htm b/modules/luci-mod-system/luasrc/view/admin_system/upgrade.htm
new file mode 100644
index 0000000000..597ddfd6bf
--- /dev/null
+++ b/modules/luci-mod-system/luasrc/view/admin_system/upgrade.htm
@@ -0,0 +1,65 @@
+<%#
+ Copyright 2008 Steven Barth
+ Copyright 2008-2009 Jo-Philipp Wich
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
+
<%:Flash Firmware%> - <%:Verify%>
+
+ <%_ The flash image was uploaded.
+ Below is the checksum and file size listed,
+ compare them with the original file to ensure data integrity.
+ Click "Proceed" below to start the flash procedure. %>
+
+ <% if storage > 0 and size > storage then %>
+
+
<%:It appears that you are trying to
+ flash an image that does not fit into the flash memory, please verify
+ the image file! %>