diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2009-09-26 11:10:01 +0000 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2009-09-26 11:10:01 +0000 |
commit | 4d3ddb03a308629abc4f9c37686c5d2351ce5950 (patch) | |
tree | d3af4c63fa8d96b07d8ff9f9e934ea79985f9db0 | |
parent | 7bd891326df0eb265a9f26fadf1c5a1764a8faa4 (diff) |
modules/admin-full: initial work on site survey and network join
4 files changed, 582 insertions, 1 deletions
diff --git a/modules/admin-full/luasrc/controller/admin/network.lua b/modules/admin-full/luasrc/controller/admin/network.lua index 08a5dd0ef..12dd559bc 100644 --- a/modules/admin-full/luasrc/controller/admin/network.lua +++ b/modules/admin-full/luasrc/controller/admin/network.lua @@ -29,7 +29,7 @@ function index() page.title = i18n("a_n_switch") page.order = 20 - local page = entry({"admin", "network", "wireless"}, arcombine(cbi("admin_network/wireless"), cbi("admin_network/wifi")), i18n("wifi"), 15) + local page = entry({"admin", "network", "wireless"}, arcombine(template("admin_network/wifi_overview"), cbi("admin_network/wifi")), i18n("wifi"), 15) page.i18n = "wifi" page.leaf = true page.subindex = true @@ -43,6 +43,10 @@ function index() end ) + local page = entry({"admin", "network", "wireless_join"}, call("wifi_join"), nil, 16) + page.i18n = "wifi" + page.leaf = true + local page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), i18n("interfaces", "Schnittstellen"), 10) page.leaf = true page.subindex = true @@ -81,3 +85,89 @@ function index() page.order = 50 end + +function wifi_join() + local function param(x) + return luci.http.formvalue(x) + end + + local function ptable(x) + x = param(x) + return x and (type(x) ~= "table" and { x } or x) or {} + end + + local dev = param("device") + local ssid = param("join") + + if dev and ssid then + local wep = (tonumber(param("wep")) == 1) + local wpa = tonumber(param("wpa_version")) or 0 + local channel = tonumber(param("channel")) + local mode = param("mode") + local bssid = param("bssid") + + local confirm = (param("confirm") == "1") + local cancel = param("cancel") and true or false + + if confirm and not cancel then + local fixed_bssid = (param("fixed_bssid") == "1") + local replace_net = (param("replace_net") == "1") + local autoconnect = (param("autoconnect") == "1") + local attach_intf = param("attach_intf") + + local uci = require "luci.model.uci".cursor() + + if replace_net then + uci:delete_all("wireless", "wifi-iface") + end + + local wificonf = { + device = dev, + mode = (mode == "Ad-Hoc" and "adhoc" or "sta"), + ssid = ssid + } + + if attach_intf and uci:get("network", attach_intf, "ifname") then + -- target network already has a interface, make it a bridge + uci:set("network", attach_intf, "type", "bridge") + uci:save("network") + uci:commit("network") + + if autoconnect then + require "luci.sys".call("/sbin/ifup " .. attach_intf) + end + end + + if fixed_bssid then + wificonf.bssid = bssid + end + + if wep then + wificonf.encryption = "wep" + wificonf.key = param("key") + elseif wpa > 0 then + wificonf.encryption = param("wpa_suite") + wificonf.key = param("key") + end + + uci:section("wireless", "wifi-iface", nil, wificonf) + uci:delete("wireless", dev, "disabled") + uci:set("wireless", dev, "channel", channel) + + uci:save("wireless") + uci:commit("wireless") + + if autoconnect then + require "luci.sys".call("/sbin/wifi") + end + + luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless", dev)) + elseif cancel then + luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless_join?device=" .. dev)) + else + luci.template.render("admin_network/wifi_join_settings") + end + else + luci.template.render("admin_network/wifi_join") + end +end diff --git a/modules/admin-full/luasrc/view/admin_network/wifi_join.htm b/modules/admin-full/luasrc/view/admin_network/wifi_join.htm new file mode 100644 index 000000000..3963a5ae2 --- /dev/null +++ b/modules/admin-full/luasrc/view/admin_network/wifi_join.htm @@ -0,0 +1,129 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2009 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<%- + + local sys = require "luci.sys" + local utl = require "luci.util" + + function guess_wifi_signal(info) + local scale = (100 / (info.quality_max or 100) * (info.quality or 0)) + local icon + + if not info.bssid or info.bssid == "00:00:00:00:00:00" then + icon = resource .. "/icons/signal-none.png" + elseif scale < 15 then + icon = resource .. "/icons/signal-0.png" + elseif scale < 35 then + icon = resource .. "/icons/signal-0-25.png" + elseif scale < 55 then + icon = resource .. "/icons/signal-25-50.png" + elseif scale < 75 then + icon = resource .. "/icons/signal-50-75.png" + else + icon = resource .. "/icons/signal-75-100.png" + end + + return icon + end + + function percent_wifi_signal(info) + local qc = info.quality or 0 + local qm = info.quality_max or 0 + + if info.bssid and qc > 0 and qm > 0 then + return math.floor((100 / qm) * qc) + else + return 0 + end + end + + function format_wifi_encryption(info) + if info.wep == true and not info.wpa_version then + return "WEP" + elseif info.wpa_version then + return "<abbr title='Pairwise: %s / Group: %s'>%s - %s</abbr>" % { + table.concat(info.pair_ciphers, ", "), + table.concat(info.group_ciphers, ", "), + (info.wpa_version == 3) and "mixed WPA/WPA2" + or (info.wpa_version == 2 and "WPA2" or "WPA"), + table.concat(info.auth_suites, ", ") + } + else + return "<em>None</em>" + end + end + + local dev = luci.http.formvalue("device") + local iw = luci.sys.wifi.getiwinfo(dev) +-%> + +<%+header%> + +<h2><a id="content" name="content"><%:a_s_iw_scan Wireless Scan%></a></h2> + +<div class="cbi-map"> + <fieldset class="cbi-section"> + <table class="cbi-section-table" style="empty-cells:hide"> + <!-- scan list --> + <% for i, net in ipairs(iw.scanlist) do %> + <tr class="cbi-section-table-row cbi-rowstyle-<%=1 + ((i-1) % 2)%>"> + <td class="cbi-value-field" style="width:16px; padding:3px"> + <abbr title="Signal: <%=net.signal%> dB / Quality: <%=net.quality%>/<%=net.quality_max%>"> + <img src="<%=guess_wifi_signal(net)%>" /><br /> + <small><%=percent_wifi_signal(net)%>%</small> + </abbr> + </td> + <td class="cbi-value-field" style="vertical-align:middle; text-align:left; padding:3px"> + <big><strong><%=net.ssid and utl.pcdata(net.ssid) or "<em>hidden</em>"%></strong></big><br /> + <strong>Channel:</strong> <%=net.channel%> | + <strong>Mode:</strong> <%=net.mode%> | + <strong>BSSID:</strong> <%=net.bssid%> | + <strong>Encryption:</strong> <%=format_wifi_encryption(net)%> + </td> + <td class="cbi-value-field" style="width:40px"> + <form action="<%=REQUEST_URI%>" method="post"> + <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" /> + <input type="hidden" name="join" value="<%=utl.pcdata(net.ssid)%>" /> + <input type="hidden" name="mode" value="<%=net.mode%>" /> + <input type="hidden" name="bssid" value="<%=net.bssid%>" /> + <input type="hidden" name="channel" value="<%=net.channel%>" /> + <input type="hidden" name="wep" value="<%=net.wep and 1 or 0%>" /> + <% if net.wpa_version then %> + <input type="hidden" name="wpa_version" value="<%=net.wpa_version%>" /> + <% for _, v in ipairs(net.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>" /> + <% end; for _, v in ipairs(net.group_ciphers) do %><input type="hidden" name="wpa_group" value="<%=v%>" /> + <% end; for _, v in ipairs(net.pair_ciphers) do %><input type="hidden" name="wpa_pairwise" value="<%=v%>" /> + <% end; end %> + + <input class="cbi-button-apply" type="submit" value="Join Network" /> + </form> + </td> + </tr> + <% end %> + <!-- /scan list --> + </table> + </fieldset> +</div> +<div class="cbi-page-actions right"> + <form class="inline" action="<%=luci.dispatcher.build_url("admin/network/wireless")%>" method="get"> + <input class="cbi-button-reset" type="submit" value="<%:a_s_iw_back_overview Back to overview%>" /> + </form> + <form class="inline" action="<%=REQUEST_URI%>" method="get"> + <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" /> + <input class="cbi-input-find" type="submit" value="<%:a_s_iw_scan_repeat Repeat scan%>" /> + </form> +</div> + +<%+footer%> diff --git a/modules/admin-full/luasrc/view/admin_network/wifi_join_settings.htm b/modules/admin-full/luasrc/view/admin_network/wifi_join_settings.htm new file mode 100644 index 000000000..c914f3edd --- /dev/null +++ b/modules/admin-full/luasrc/view/admin_network/wifi_join_settings.htm @@ -0,0 +1,112 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2009 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<%- + + local sys = require "luci.sys" + local utl = require "luci.util" + local uci = require "luci.model.uci".cursor_state() + + local ifaces = { } + uci:foreach("network", "interface", function(i) + if i.ifname ~= "lo" then + ifaces[#ifaces+1] = { i['.name'], i.ifname, i.ipaddr } + end + end) + + local dev = luci.http.formvalue("device") + local iw = luci.sys.wifi.getiwinfo(dev) + +-%> + +<%+header%> + +<h2><a id="content" name="content"><%:a_s_iw_join Join Network%></a></h2> + +<form method="post" action="<%=REQUEST_URI%>"> + <div class="cbi-map"> + <div class="cbi-map-descr"> + <%=luci.i18n.translatef("a_s_iw_join_desc", "You are about to join the wireless network <em><strong>%s</strong></em>. " .. + "In order to complete the process, you need to provide some additional details.", + utl.pcdata(luci.http.formvalue("join") or "(hidden)") + )%> + </div> + + <fieldset class="cbi-section"> + <input type="hidden" name="confirm" value="1" /> + <input type="hidden" name="join" value="<%=utl.pcdata(luci.http.formvalue("join"))%>" /> + <input type="hidden" name="device" value="<%=utl.pcdata(luci.http.formvalue("device"))%>" /> + <input type="hidden" name="mode" value="<%=luci.http.formvalue("mode")%>" /> + <input type="hidden" name="bssid" value="<%=luci.http.formvalue("bssid")%>" /> + <input type="hidden" name="channel" value="<%=luci.http.formvalue("channel")%>" /> + <input type="hidden" name="wep" value="<%=luci.http.formvalue("wep")%>" /> + <input type="hidden" name="wpa_version" value="<%=luci.http.formvalue("wpa_version")%>" /> + + <% if luci.http.formvalue("wep") == "1" then %> + <label for="pw_key">WEP passphrase</label><br /> + <input class="cbi-input-password" type="password" name="key" id="pw_key" /> + <br /><br /> + <% elseif tonumber(luci.http.formvalue("wpa_version") or 0) > 0 and luci.http.formvalue("wpa_suites") == "PSK" then %> + <label for="pw_key">WPA passphrase</label><br /> + <input class="cbi-input-password" type="password" name="key" id="pw_key" /> + + <% if tonumber(luci.http.formvalue("wpa_version") or 0) == 3 then %> + <select name="wpa_suite"> + <option value="psk">WPA-PSK</option> + <option value="psk2" selected="selected">WPA2-PSK</option> + <option value="psk+psk2">WPA/WPA2-PSK mixed mode</option> + </select> + <% else %> + <input type="hidden" name="wpa_suite" value="psk<%=tonumber(luci.http.formvalue("wpa_version") or 0) == 2 and 2%>" /> + <% end %> + + <br /><br /> + <% end %> + + <label for="sel_attach_intf">Attach wireless to</label><br /> + <select name="attach_intf" id="sel_attach_intf"> + <% for _, i in ipairs(ifaces) do %> + <option<% if i[1] == "wan" then %> selected="selected"<% end %> value="<%=i[1]%>"><%=i[1]%> (<%=i[2]%><% if i[3] then %> - <%=i[3]%><% end %>)</option> + <% end %> + <option value="">-- no interface --</option> + </select> + + <br/><br /> + <hr /><br /> + + <% if luci.http.formvalue("mode") == "Ad-Hoc" then %> + <input type="checkbox" name="fixed_bssid" value="1" id="cb_fixed_bssid" checked="checked" /> + <label for="cb_fixed_bssid">Lock to BSSID <%=luci.http.formvalue("bssid")%></label> + <br /> + <% end %> + + <% if iw.mbssid_support then %> + <input type="checkbox" name="replace_net" value="1" id="cb_replace_net" checked="checked" /> + <label for="cb_replace_net">Overwrite existing wireless configuration</label> + <br /> + <% else %> + <input type="hidden" name="replace_net" value="1" /> + <% end %> + + <input type="checkbox" name="autoconnect" value="1" id="cb_autoconnect" checked="checked" /> + <label for="cb_autoconnect">Automatically connect</label> + </fieldset> + </div> + <div class="cbi-page-actions"> + <input class="cbi-button-apply" type="submit" value="<%:a_s_iw_join_confirm Join network%>" /> + <input class="cbi-button-reset" type="submit" name="cancel" value="<%:a_s_iw_back_scan Back to scan results%>" /> + </div> +</form> + +<%+footer%> diff --git a/modules/admin-full/luasrc/view/admin_network/wifi_overview.htm b/modules/admin-full/luasrc/view/admin_network/wifi_overview.htm new file mode 100644 index 000000000..251f767d2 --- /dev/null +++ b/modules/admin-full/luasrc/view/admin_network/wifi_overview.htm @@ -0,0 +1,250 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008-2009 Steven Barth <steven@midlink.org> +Copyright 2008-2009 Jo-Philipp Wich <xm@leipzig.freifunk.net> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<%- + + local sys = require "luci.sys" + local utl = require "luci.util" + local uci = require "luci.model.uci".cursor_state() + + function guess_wifi_hw(ifname) + local name, idx = ifname:match("^([a-z]+)(%d+)") + idx = tonumber(idx) + + -- wl.o + if name == "wl" then + local name = "Broadcom 802.11 Wireless Controller" + 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 = string.format( + "Broadcom BCM%04x 802.11 Wireless Controller", + tonumber(version, 16) + ) + + break + else + nm = nm + 1 + end + end + end + fd:close() + end + + return name + + -- madwifi + elseif name == "ath" or name == "wifi" then + return "Atheros 802.11 Wireless Controller" + + -- ralink + elseif name == "ra" then + return "RaLink 802.11 Wireless Controller" + + -- prism? + elseif name == "eth" then + return "Prism 802.11 Wireless Controller" + + -- dunno yet + else + return "Unkown 802.11 Wireless Controller" + end + end + + function guess_wifi_signal(info) + local snr = -1 * ((info.noise or 0) - (info.signal or 0)) + local scale = math.floor(snr / 5) + local icon + + if not info.bssid or info.bssid == "00:00:00:00:00:00" then + icon = resource .. "/icons/signal-none.png" + elseif scale < 1 then + icon = resource .. "/icons/signal-0.png" + elseif scale < 2 then + icon = resource .. "/icons/signal-0-25.png" + elseif scale < 3 then + icon = resource .. "/icons/signal-25-50.png" + elseif scale < 4 then + icon = resource .. "/icons/signal-50-75.png" + else + icon = resource .. "/icons/signal-75-100.png" + end + + return icon + end + + function percent_wifi_signal(info) + local qc = info.quality or 0 + local qm = info.quality_max or 0 + + if info.bssid and qc > 0 and qm > 0 then + return math.floor((100 / qm) * qc) + else + return 0 + end + end + + function find_wifi_devices() + local devs = { } + uci:foreach("wireless", "wifi-device", + function(s) + local dev = s['.name'] + local act = 0 + devs[dev] = { active = 0, networks = { } } + + uci:foreach("wireless", "wifi-iface", + function(s) + if s.device == dev then + if s.up == "1" then act = act + 1 end + devs[dev].networks[#devs[dev].networks+1] = { + active = (s.up == "1"), + ifname = s.ifname, + info = sys.wifi.getiwinfo(s.ifname or s.device) + } + end + end) + + devs[dev].hwname = guess_wifi_hw(dev) + devs[dev].active = (act > 0) + end) + + return devs + end + + function find_wifi_frequency(state) + if state.active then + return string.format("%d (%.03f GHz)", + state.networks[1].info.channel, + state.networks[1].info.frequency / 1000); + else + return "n/a" + end + end + + + local devices = find_wifi_devices() + local arpcache = { } + sys.net.arptable(function(e) arpcache[e["HW address"]] = e["IP address"] end) +-%> + +<%+header%> + +<h2><a id="content" name="content"><%:a_s_iw_overview Wireless Overview%></a></h2> + +<div class="cbi-map"> + + <% for dev, state in utl.kspairs(devices) do %> + <!-- device <%=dev%> --> + <fieldset class="cbi-section"> + <table class="cbi-section-table" style="margin:10px; empty-cells:hide"> + <!-- physical device --> + <tr> + <td style="width:34px"><img src="<%=resource%>/icons/wifi<%=state.active and "" or "_disabled"%>.png" style="float:left; margin-right:10px" /></td> + <td colspan="2" style="text-align:left"> + <big><strong><%=state.hwname%> (<%=dev%>)</strong></big><br /> + <strong>Channel:</strong> <%=find_wifi_frequency(state)%> | + <strong>Bitrate:</strong> <%=state.active and (state.networks[1].info.bitrate / 1000) .. " Mb/s" or "n/a"%> + </td> + <td style="width:40px"> + <a href="<%=luci.dispatcher.build_url("admin/network/wireless_join?device="..dev)%>"><img style="border:none" src="<%=resource%>/cbi/find.gif" alt="Find and join network" title="Find and join network" /></a> + <a href="#"><img style="border:none" src="<%=resource%>/cbi/add.gif" alt="Provide new network" title="Provide new network" /></a> + </td> + </tr> + <!-- /physical device --> + + <!-- network list --> + <% if #state.networks > 0 then %> + <% for i, net in ipairs(state.networks) do %> + <tr class="cbi-section-table-row cbi-rowstyle-<%=1 + ((i-1) % 2)%>"> + <td></td> + <td class="cbi-value-field" style="width:16px; padding:3px"> + <img src="<%=guess_wifi_signal(net.info)%>" title="Signal: <%=net.info.signal%> dBm / Noise: <%=net.info.noise%> dBm" /><br /> + <small><%=percent_wifi_signal(net.info)%>%</small> + </td> + <td class="cbi-value-field" style="vertical-align:middle; text-align:left; padding:3px"> + <strong>SSID:</strong> <%=utl.pcdata(net.info.ssid)%> | + <strong>Mode:</strong> <%=net.info.mode%><br /> + <strong>BSSID:</strong> <%=net.info.bssid%> | + <strong>Encryption:</strong> <%=net.info.enctype%> + </td> + <td class="cbi-value-field" style="width:40px"> + <a href="<%=REQUEST_URI%>/<%=dev%>"><img style="border:none" src="<%=resource%>/cbi/edit.gif" alt="Edit this network" title="Edit this network" /></a> + <a href="#"><img style="border:none" src="<%=resource%>/cbi/remove.gif" alt="Delete this network" title="Delete this network" /></a> + </td> + </tr> + <% end %> + <% else %> + <tr class="cbi-section-table-row cbi-rowstyle-2"> + <td></td> + <td colspan="3" class="cbi-value-field" style="vertical-align:middle; text-align:left; padding:3px"> + <em>(No network configured on this device)</em> + </td> + </tr> + <% end %> + <!-- /network list --> + </table> + </fieldset> + <!-- /device <%=dev%> --> + <% end %> + + + + + <h2><a id="content" name="content"><%:a_s_iw_overview2 Associated Stations%></a></h2> + + <fieldset class="cbi-section"> + <table class="cbi-section-table" style="margin:10px; width:50%"> + <tr class="cbi-section-table-titles"> + <th class="cbi-section-table-cell"></th> + <th class="cbi-section-table-cell">SSID</th> + <th class="cbi-section-table-cell">MAC</th> + <th class="cbi-section-table-cell">Address</th> + <th class="cbi-section-table-cell">Signal</th> + <th class="cbi-section-table-cell">Noise</th> + </tr> + + <% local count = -1 %> + <% for dev, state in utl.kspairs(devices) do %> + <% for _, net in ipairs(state.networks) do %> + <% for mac, info in utl.kspairs(net.info.assoclist) do info.bssid = mac; count = count + 1 %> + <tr class="cbi-section-table-row cbi-rowstyle-<%=1 + (count % 2)%>"> + <td class="cbi-value-field"><img src="<%=guess_wifi_signal(info)%>" title="Signal: <%=info.signal%> dBm / Noise: <%=info.noise%> dBm" /></td> + <td class="cbi-value-field"><%=net.info.ssid%></td> + <td class="cbi-value-field"><%=mac%></td> + <td class="cbi-value-field"><%=arpcache[mac] or "n/a"%></td> + <td class="cbi-value-field"><%=info.signal%> dBm</td> + <td class="cbi-value-field"><%=info.noise%> dBm</td> + </tr> + <% end %> + <% end %> + <% end %> + <% if count <= 0 then %> + <tr class="cbi-section-table-row cbi-rowstyle-2"> + <td class="cbi-value-field" colspan="6"> + <em>No information available</em> + </td> + </tr> + <% end %> + </table> + </fieldset> +</div> + +<%+footer%> |