Add reconfiguration interface to support more generic and readable reconfiguring; fix js/jq URLs; misc minor fixes.

This commit is contained in:
Wouter R 2013-04-08 01:20:45 +02:00
parent 5b0e219ef6
commit 1f39bf6434
10 changed files with 326 additions and 91 deletions

View File

@ -3,8 +3,8 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15" />
<title>Wireless configuration</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="autowifi.js"></script>
<script type="text/javascript" src="/admin/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="/admin/autowifi.js"></script>
<link href="/admin/autowifi.css" rel="stylesheet" type="text/css" />
</head>
@ -28,10 +28,10 @@
<input id="wlan_btn_connect" disabled type="button" value="Connect" />
</form>
</div>
<div class="catgroup">
<div class="catgroup">
<span class="cattitle">Known networks</span>
<div id="wlan_known_container"></div>
</div>
</body>
</body>
</html>

View File

@ -55,9 +55,11 @@ function fetchNetworkState() {
if (data.status == "ERR") setResult(data.msg, true);
var net = parseNetLine(data.payload);
var modeText = "Unknown device mode ('" + net.mode + "')";
if (net.mode == "ap") modeText = "Access point mode";
else if (net.mode == "sta") modeText = "Client mode";
$("#wlan_state").text(modeText + " (SSID: " + net.ssid + "; BSSID: " + net.bssid + "; channel: " + net.channel + ")");
if (net.mode == "ap") {
$("#wlan_state").text("Access point mode");
} else if (net.mode == "sta") {
$("#wlan_state").text("Client mode (SSID: " + net.ssid + "; BSSID: " + net.bssid + "; channel: " + net.channel + ")");
}
});
}
@ -72,8 +74,9 @@ function fetchAvailableNetworks() {
options.empty();
$.each(data, function(index,value) {
if (value != "") {
var ssid = parseNetLine(value).ssid;
options.append($("<option />").val(ssid).text(ssid));
var netinf = parseNetLine(value);
var ssid = netinf.ssid;
options.append($("<option />").val(ssid).text(ssid + " - " + netinf.mode + " mode"));
}
});
$("#wlan_btn_connect").prop('disabled', false);

5
src/admin/jquery-1.9.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -14,10 +14,11 @@
http://wiki.openwrt.org/doc/howto/wireless.hotspot
]]
--print ("HTTP/1.0 200 OK")
print ("Content-type: text/plain\r\n")
io.write ("Content-type: text/plain\r\n\r\n")
local util = require("util")
local u = require("util")
local wifi = require("wifihelper")
local reconf = require("reconf")
local uci = require("uci").cursor()
local urlcode = require("urlcode")
local iwinfo = require("iwinfo")
@ -26,6 +27,7 @@ local argOperation, argDevice, argSsid, argPhrase, argRecreate
local errortext = nil
function init()
u:initlog(u.LOG_LEVEL.debug, true, io.stderr)
local qs = os.getenv("QUERY_STRING")
local urlargs = {}
urlcode.parsequery(qs, urlargs)
@ -53,7 +55,7 @@ function init()
return false
end
return wifi.init()
return wifi.init() and reconf.init(wifi, true)
end
@ -61,19 +63,24 @@ function main()
if argOperation == "getavl" then
local sr = wifi.getScanInfo()
local si, se
--TODO:
-- - extend reconf interface to support function arguments (as tables) so wifihelper functionality can be integrated
-- but how? idea: pass x_args={arg1="a",arg2="2342"} with component 'x'
if sr and #sr > 0 then
util.printWithSuccess(#sr .. " network(s) found");
u.printWithSuccess(#sr .. " network(s) found");
for _, se in ipairs(sr) do
--print("[[ " .. util.dump(se) .. " ]]") --TEMP
print(se.ssid .. "," .. se.bssid .. "," .. se.channel .. "," .. wifi.mapDeviceMode(se.mode))
print("[[ " .. u.dump(se) .. " ]]") --TEMP
if se.mode ~= "ap" then
print(se.ssid .. "," .. se.bssid .. "," .. se.channel .. "," .. wifi.mapDeviceMode(se.mode))
end
end
else
util.exitWithError("No scan results or scanning not possible")
u.exitWithError("No scan results or scanning not possible")
end
elseif argOperation == "getknown" then
util.printWithSuccess("")
u.printWithSuccess("")
for _, net in ipairs(wifi.getConfigs()) do
if net.mode == "sta" then
local bssid = net.bssid or "<unknown BSSID>"
@ -87,11 +94,11 @@ function main()
local ssid = ds.ssid or "<unknown SSID>"
local bssid = ds.bssid or "<unknown BSSID>"
local channel = ds.channel or "<unknown channel>"
util.printWithSuccess("");
u.printWithSuccess("");
print(ssid .. "," .. bssid .. "," .. channel .. "," .. ds.mode)
elseif argOperation == "assoc" then
if argSsid == nil or argSsid == "" then util.exitWithError("Please supply an SSID to associate with") end
if argSsid == nil or argSsid == "" then u.exitWithError("Please supply an SSID to associate with") end
local cfg = nil
for _, net in ipairs(wifi.getConfigs()) do
@ -106,40 +113,46 @@ function main()
wifi.createConfigFromScanInfo(scanResult)
else
--check for error
util.exitWithError("No wireless network with SSID '" .. argSsid .. "' is available")
u.exitWithError("No wireless network with SSID '" .. argSsid .. "' is available")
end
end
wifi.activateConfig(argSsid)
local rv = wifi.restart()
util.exitWithSuccess("Wlan associated with network "..argSsid.."! [$?=" .. rv .. "]")
u.exitWithSuccess("Wlan associated with network "..argSsid.."! [$?=" .. rv .. "]")
elseif argOperation == "disassoc" then
wifi.activateConfig()
local rv = wifi.restart()
util.exitWithSuccess("Deactivated all wireless networks [$?=" .. rv .. "]")
u.exitWithSuccess("Deactivated all wireless networks [$?=" .. rv .. "]")
elseif argOperation == "openap" then
--add AP net, activate it, deactivate all others, reload network/wireless config, add all dhcp and captive settings and reload as needed
reconf.switchConfiguration{apnet="add_noreload"}
wifi.activateConfig(wifi.AP_SSID)
wifi.configureDhcp(true)
local rv = wifi.restart(true)
util.exitWithSuccess("Switched to AP mode (SSID: '" .. wifi.AP_SSID .. "') [$?=" .. rv .. "]")
reconf.switchConfiguration{ network="reload", staticaddr="add", dhcppool="add", wwwredir="add", dnsredir="add", wwwcaptive="add", natreflect="add" }
u.exitWithSuccess("Switched to AP mode (SSID: '" .. wifi.AP_SSID .. "')")
elseif argOperation == "rm" then
if argSsid == nil or argSsid == "" then util.exitWithError("Please supply an SSID to remove") end
if argSsid == nil or argSsid == "" then u.exitWithError("Please supply an SSID to remove") end
if wifi.removeConfig(argSsid) then
util.exitWithSuccess("Removed wireless network with SSID " .. argSsid)
u.exitWithSuccess("Removed wireless network with SSID " .. argSsid)
else
util.exitWithWarning("No wireless network with SSID " .. argSsid)
u.exitWithWarning("No wireless network with SSID " .. argSsid)
end
elseif argOperation == "test" then
reconf.switchConfiguration{ apnet="rm", staticaddr="rm", dhcppool="rm", wwwredir="rm", dnsredir="rm", wwwcaptive="rm", natreflect="rm" }
-- reconf.switchConfiguration{dnsredir="add"}
u.exitWithSuccess("nop")
elseif argOperation == "auto" then
util.exitWithWarning("Not implemented");
u.exitWithWarning("Not implemented");
--scan nets
--take union of scan and known
--connect to first if not empty; setup ap otherwise
else
util.exitWithError("Unknown operation: '" .. argOperation .. "'")
u.exitWithError("Unknown operation: '" .. argOperation .. "'")
end
os.exit(0)
@ -150,11 +163,7 @@ end
--[[ START OF CODE ]]--
if init() == false then
util.exitWithError(errortext)
end
if wifi.createOrReplaceApConfig(true) == false then
util.exitWithError(errortext)
u.exitWithError(errortext)
end
main()

View File

1
src/ext/www/cgi-bin/wfcf Symbolic link
View File

@ -0,0 +1 @@
/usr/share/lua/autowifi/ext/wfcf

View File

@ -5,6 +5,6 @@
<meta http-equiv="refresh" content="0; URL=/admin/autowifi.html" />
</head>
<body style="background-color: black">
<a style="color: white; text-decoration: none" href="/admin/autowifi.html">LuCI - Lua Configuration Interface</a>
<a style="color: white; text-decoration: none" href="/admin/autowifi.html">Doodle 3D - Wireless Network Configuration</a>
</body>
</html>

222
src/reconf.lua Normal file
View File

@ -0,0 +1,222 @@
local u = require("util")
local uci = require("uci").cursor()
local M = {}
local reconf = {}
local wifi
local reloadSilent
M.WWW_CAPTIVE_PATH = "/usr/share/lua/autowifi/ext/www"
M.WWW_CAPTIVE_INDICATOR = "/www/.autowifi-inplace"
M.WWW_RENAME_NAME = "/www-regular"
function M.init(wifiInstance, reloadSilent)
wifi = wifiInstance
silent = reloadSilent or false
return true
end
--- Switch configuration between AP and station modes
-- @param components a table with components as keys with operations as values (add or remove)
-- Valid components (each with add and rm operation) are: apnet, staticaddr, dhcppool, wwwredir, dnsredir, wwwcaptive, natreflect.
-- and additionally: wifiiface/add, network/reload
function M.switchConfiguration(components)
local dirtyList = {} -- laundry list, add config/script name as key with value c (commit), r (reload) or b (both)
for k,v in pairs(components) do
local fname = k .. "_" .. v
if type(reconf[fname]) == "function" then
u:logdebug("reconfiguring component '" .. k .. "' (" .. v .. ")")
reconf[fname](dirtyList)
else
u:logwarn("unknown component or action '" .. fname .. "' skipped")
end
end
-- first run all commits, then perform reloads
for k,v in pairs(dirtyList) do
if v == "c" or v == "b" then M.commitComponent(k) end
end
for k,v in pairs(dirtyList) do
if v == "r" or v == "b" then M.reloadComponent(k, silent) end
end
end
function M.commitComponent(c)
u:loginfo("committing component '" .. c .. "'")
uci:commit(c)
end
function M.reloadComponent(c, silent)
u:loginfo("reloading component '" .. c .. "'")
if silent ~= nil and silent then os.execute("/etc/init.d/" .. c .. " reload &> /dev/null")
else os.execute("/etc/init.d/" .. c .. " reload") end
end
function M.uciTableSet(config, section, options)
for k, v in pairs(options) do uci:set(config, section, k, v) end
end
--[[ Issue '/etc/init.d/network reload' command ]]
function reconf.network_reload(dirtyList) dirtyList.network = "r" end
--[[ Add wlan interface declaration to /etc/config/network ]]
function reconf.wifiiface_add(dirtyList)
uci:set("network", wifi.NET, "interface")
dirtyList.network = "c";
end
--[[ Add/remove access point network ]]
function reconf.apnet_add_noreload(dirtyList) reconf.apnet_add(dirtyList, true) end
function reconf.apnet_add(dirtyList, noReload)
local sname = nil
uci:foreach("wireless", "wifi-iface", function(s)
if s.ssid == wifi.AP_SSID then sname = s[".name"]; return false end
end)
if sname == nil then sname = uci:add("wireless", "wifi-iface") end
M.uciTableSet("wireless", sname, {
network = wifi.NET,
ssid = wifi.AP_SSID,
encryption = "none",
device = "radio0",
mode = "ap",
})
dirtyList.wireless = "c"
if noReload == nil or noReload == false then dirtyList.network = "r" end
end
function reconf.apnet_rm(dirtyList)
local sname = nil
uci:foreach("wireless", "wifi-iface", function(s)
if s.ssid == wifi.AP_SSID then sname = s[".name"]; return false end
end)
if sname == nil then
u:loginfo("AP network configuration does not exist, nothing to remove")
return true
end
uci:delete("wireless", sname)
dirtyList.network = "r"; dirtyList.wireless = "c"
end
--[[ Switch between wireless static IP and DHCP ]]
function reconf.staticaddr_add(dirtyList)
-- M.uciTableSet("network", wifi.NET, {
-- proto = "static",
-- ipaddr = wifi.AP_ADDRESS,
-- netmask = wifi.AP_NETMASK,
-- type = "bridge",
-- })
uci:set("network", wifi.NET, "proto", "static")
uci:set("network", wifi.NET, "ipaddr", wifi.AP_ADDRESS)
uci:set("network", wifi.NET, "netmask", wifi.AP_NETMASK)
uci:set("network", wifi.NET, "type", "bridge")
dirtyList.network = "b"
end
--TODO: replace repeated deletes by M.uciTableDelete
function reconf.staticaddr_rm(dirtyList)
uci:set("network", wifi.NET, "proto", "dhcp")
uci:delete("network", wifi.NET, "ipaddr")
uci:delete("network", wifi.NET, "netmask")
uci:delete("network", wifi.NET, "type")
dirtyList.network = "b"
end
--[[ Add/remove DHCP pool for wireless net ]]
function reconf.dhcppool_add(dirtyList)
-- M.uciTableSet("dhcp", wifi.NET, {
-- interface = wifi.NET,
-- start = "100",
-- limit = "150",
-- leasetime = "12h",
-- })
uci:set("dhcp", wifi.NET, "dhcp") --create section??? TODO: what was this again
uci:set("dhcp", wifi.NET, "interface", wifi.NET)
uci:set("dhcp", wifi.NET, "start", "100")
uci:set("dhcp", wifi.NET, "limit", "150")
uci:set("dhcp", wifi.NET, "leasetime", "12h")
dirtyList.dhcp = "c"; dirtyList.dnsmasq = "r"
end
function reconf.dhcppool_rm(dirtyList)
uci:delete("dhcp", wifi.NET)
dirtyList.dhcp = "c"; dirtyList.dnsmasq = "r"
end
--[[ Add/remove webserver 404 redirection and denial of dirlisting ]]
function reconf.wwwredir_add(dirtyList)
uci:set("uhttpd", "main", "error_page", "/admin/autowifi.html")
uci:set("uhttpd", "main", "no_dirlist", "1")
dirtyList.uhttpd = "b"
end
function reconf.wwwredir_rm(dirtyList)
uci:delete("uhttpd", "main", "error_page")
uci:delete("uhttpd", "main", "no_dirlist")
dirtyList.uhttpd = "b"
end
--[[ Add/remove redirecton of all DNS requests to self ]]
function reconf.dnsredir_add(dirtyList)
local redirText = "/#/" .. wifi.AP_ADDRESS
local sname = u.getUciSectionName("dhcp", "dnsmasq")
if sname == nil then
u:logerror("dhcp config does not contain a dnsmasq section")
return false
end
if uci:get("dhcp", sname, "address") ~= nil then
u:logdebug("DNS address redirection already in place, not re-adding")
return true
end
uci:set("dhcp", sname, "address", {redirText})
dirtyList.dhcp = "c"; dirtyList.dnsmasq = "r"
end
function reconf.dnsredir_rm(dirtyList)
local sname = u.getUciSectionName("dhcp", "dnsmasq")
if sname == nil then
u:logerror("dhcp config does not contain a dnsmasq section")
return false
end
uci:delete("dhcp", sname, "address")
dirtyList.dhcp = "c"; dirtyList.dnsmasq = "r"
end
--TODO: handle os.rename() return values (nil+msg on error)
function reconf.wwwcaptive_add(dirtyList)
if u.exists(M.WWW_CAPTIVE_INDICATOR) then
u:logdebug("WWW captive directory already in place, not redoing")
return true
end
os.rename("/www", M.WWW_RENAME_NAME)
u.symlink(M.WWW_CAPTIVE_PATH, "/www")
return true
end
function reconf.wwwcaptive_rm(dirtyList)
if not u.exists(M.WWW_CAPTIVE_INDICATOR) then
u:logdebug("WWW captive directory not in place, not undoing")
return true
end
os.remove("/www")
return os.rename(M.WWW_RENAME_NAME, "/www")
end
--[[ Setup/remove NAT reflection to redirect all IPs ]]
function reconf.natreflect_add(dirtyList)
uci:set("firewall", "portalreflect", "redirect");
M.uciTableSet("firewall", "portalreflect", {
src = "lan",
proto = "tcp",
src_dport = "80",
dest_port = "80",
dest_ip = wifi.AP_ADDRESS,
target = "DNAT"
})
dirtyList.firewall = "b"
end
function reconf.natreflect_rm(dirtyList)
uci:delete("firewall", "portalreflect")
dirtyList.firewall = "b"
end
return M

View File

@ -1,3 +1,5 @@
local uci = require("uci").cursor()
local M = {}
function M.dump(o)
@ -33,4 +35,49 @@ function M.exitWithError(msg)
os.exit(1)
end
function M.getUciSectionName(config, type)
local sname = nil
uci:foreach(config, type, function(s) sname = s[".name"] end)
return sname
end
function M.exists(file)
local r = io.open(file) --ignore returned message
if r ~= nil then io.close(r) end
return r ~= nil
end
function M.symlink(from, to)
if from == nil or from == "" or to == nil or to == "" then return -1 end
local x = "ln -s " .. from .. " " .. to
return os.execute(x)
end
-- logging
M.LOG_LEVEL = {debug = 1, info = 2, warn = 3, error = 4, fatal = 5}
local logLevel, logVerbose, logStream
function M:initlog(level, verbose, stream)
logLevel = level or M.LOG_LEVEL.warn
logVerbose = verbose or false
logStream = stream or io.stdout
end
local function log(level, msg, verbose)
if level >= logLevel then
local now = os.date("%m-%d %H:%M:%S")
local i = debug.getinfo(3)
local v = verbose ~= nil and verbose or logVerbose
if v then logStream:write(now .. " (" .. level .. ") \t" .. msg .. " [" .. i.name .. "@" .. i.short_src .. ":" .. i.linedefined .. "]\n")
else logStream:write(now .. " (" .. level .. ") \t" .. msg .. "\n") end
end
end
function M:logdebug(msg, verbose) log(M.LOG_LEVEL.debug, msg, verbose) end
function M:loginfo(msg, verbose) log(M.LOG_LEVEL.info, msg, verbose) end
function M:logwarn(msg, verbose) log(M.LOG_LEVEL.warn, msg, verbose) end
function M:logerror(msg, verbose) log(M.LOG_LEVEL.error, msg, verbose) end
function M:logfatal(msg, verbose) log(M.LOG_LEVEL.fatal, msg, verbose) end
return M

View File

@ -1,4 +1,4 @@
local util = require("util")
local reconf = require("reconf")
local uci = require("uci").cursor()
local iwinfo = require("iwinfo")
@ -136,33 +136,6 @@ function M.createConfigFromScanInfo(info, passphrase, disabled)
uci:commit("wireless")
end
--- Ensure a suitable config section for the access point network exists
-- @param disabled flag the network as disabled (optional)
function M.createOrReplaceApConfig(disabled)
local sname = nil
uci:foreach("wireless", "wifi-iface", function(s)
if s.ssid == M.AP_SSID then
sname = s[".name"]
return false
end
end)
if sname == nil then sname = uci:add("wireless", "wifi-iface") end
local apconfig = {
network = M.NET,
ssid = M.AP_SSID,
encryption = "none",
device = "radio0",
mode = "ap",
}
apconfig.disabled = disabled ~= nil and disabled and 1 or 0
for k, v in pairs(apconfig) do
uci:set("wireless", sname, k, v)
end
uci:commit("wireless")
end
--- Reload network config to reflect contents of config
-- @see http://wiki.openwrt.org/doc/techref/netifd)
-- * Network reload only restarts interfaces which need to be restarted so no
@ -176,29 +149,4 @@ function M.restart(dhcpToo)
return 0
end
--- Add or remove DHCP section for wlan network
-- @param addCfg add section if true or nil, remove it if false
function M.configureDhcp(addCfg)
if addCfg == nil or addCfg == true then
uci:set("dhcp", M.NET, "dhcp")
uci:set("dhcp", M.NET, "interface", M.NET)
uci:set("dhcp", M.NET, "start", "100")
uci:set("dhcp", M.NET, "limit", "150")
uci:set("dhcp", M.NET, "leasetime", "12h")
uci:set("network", M.NET, "proto", "static")
uci:set("network", M.NET, "ipaddr", M.AP_ADDRESS)
uci:set("network", M.NET, "netmask", M.AP_NETMASK)
uci:set("network", M.NET, "type", "bridge")
else
uci:delete("dhcp", M.NET)
uci:set("network", M.NET, "proto", "dhcp")
uci:delete("network", M.NET, "ipaddr")
uci:delete("network", M.NET, "netmask")
-- uci:delete("network", M.NET, "bridge")
end
uci:commit("dhcp")
uci:commit("network")
--TODO: is network reload enough here?
end
return M