2018-01-23 14:36:03 +00:00
< %#
Copyright 2008-2009 Steven Barth < steven @ midlink . org >
Copyright 2008-2015 Jo-Philipp Wich < jow @ openwrt . org >
Licensed to the public under the Apache License 2.0.
-%>
< %-
local ip = require "luci.ip"
local fs = require "nixio.fs"
local utl = require "luci.util"
local uci = require "luci.model.uci".cursor()
local ntm = require "luci.model.network"
local has_iwinfo = pcall(require, "iwinfo")
ntm.init(uci)
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
-- ralink
elseif name == "ra" then
return translatef("RaLink 802.11%s Wireless Controller", bands)
-- hermes
elseif name == "eth" then
return translate("Hermes 802.11b Wireless Controller")
-- hostap
elseif name == "wlan" and fs.stat("/proc/net/hostap/" .. ifname, "type") == "dir" then
return translate("Prism2/2.5/3 802.11b Wireless Controller")
-- dunno yet
else
return translatef("Generic 802.11%s Wireless Controller", bands)
end
end
local devices = ntm:get_wifidevs()
local netlist = { }
local netdevs = { }
local dev
for _, dev in ipairs(devices) do
local net
for _, net in ipairs(dev:get_wifinets()) do
netlist[#netlist+1] = net:id()
netdevs[net:id()] = dev:name()
end
end
-%>
< %+header%>
< % if not has_iwinfo then %>
2018-06-04 20:13:57 +00:00
< div class = "alert-message warning" >
< h4 > < %:Package libiwinfo required!%>< / h4 >
< p > < %_The < em > libiwinfo-lua< / em > package is not installed. You must install this component for working wireless configuration!%>< / p >
2018-01-23 14:36:03 +00:00
< / div >
< % end %>
< script type = "text/javascript" src = "<%=resource%>/cbi.js" > < / script >
< script type = "text/javascript" > / / < ! [ C D A T A [
var wifidevs = < %=luci.http.write_json(netdevs)%>;
var is_reconnecting = false;
function nowrap(s) {
return s.replace(/ /g, '  ');
}
function wifirate(bss, rx) {
var p = rx ? 'rx_' : 'tx_',
s = '%.1f < %:Mbit/s%>, %d< %:MHz%>'
.format(bss[p+'rate'] / 1000, bss[p+'mhz']),
ht = bss[p+'ht'], vht = bss[p+'vht'],
mhz = bss[p+'mhz'], nss = bss[p+'nss'],
mcs = bss[p+'mcs'], sgi = bss[p+'short_gi'];
if (ht || vht) {
if (vht) s += ', VHT-MCS %d'.format(mcs);
if (nss) s += ', VHT-NSS %d'.format(nss);
if (ht) s += ', MCS %s'.format(mcs);
if (sgi) s += ', < %:Short GI%>';
}
return s;
}
function wifi_shutdown(id, toggle) {
var reconnect = (toggle.getAttribute('active') == 'false');
if (!reconnect & & !confirm(String.format('< %:Really shut down network?\nYou might lose access to this device if you are connected via this interface.%>')))
return;
is_reconnecting = true;
var s = document.getElementById('iw-rc-status');
if (s)
{
s.parentNode.style.display = 'block';
s.innerHTML = '< %:Waiting for changes to be applied...%>';
}
for (var net in wifidevs)
{
var st = document.getElementById(net + '-iw-status');
if (st)
st.innerHTML = '< em > < %:Wireless is restarting...%>< / em > ';
}
(new XHR()).post('< %=url('admin/network')%>/wireless_' + (reconnect ? 'reconnect' : 'shutdown') + '/' + id, { token: '< %=token%>' },
function(x)
{
if (s)
{
s.innerHTML = reconnect
? '< %:Wireless restarted%>'
: '< %:Wireless shut down%>';
window.setTimeout(function() {
s.parentNode.style.display = 'none';
is_reconnecting = false;
}, 1000);
}
}
);
}
function wifi_delete(id) {
if (!confirm('< %:Really delete this wireless network? The deletion cannot be undone!\nYou might lose access to this device if you are connected via this network.%>'))
return;
(new XHR()).post('< %=url('admin/network/wireless_delete')%>/' + id, { token: '< %=token%>' },
function(x) {
location.href = '< %=url('admin/network/wireless')%>';
}
);
}
var hosts = < %=luci.http.write_json(luci.sys.net.host_hints())%>;
XHR.poll(5, '< %=url('admin/network/wireless_status', table.concat(netlist, ","))%>', null,
function(x, st)
{
if (st)
{
var assoctable = document.getElementById('iw-assoclist');
if (assoctable)
2018-05-31 13:44:12 +00:00
while (assoctable.firstElementChild !== assoctable.lastElementChild)
assoctable.removeChild(assoctable.lastElementChild);
2018-01-23 14:36:03 +00:00
var devup = { };
var rowstyle = 1;
for( var i = 0; i < st.length ; i + + )
{
var iw = st[i];
var is_assoc = (iw.bssid & & iw.bssid != '00:00:00:00:00:00' & & iw.channel & & iw.mode != 'Unknown' & & !iw.disabled);
var p = iw.quality;
var q = is_assoc ? p : -1;
var icon;
if (q < 0 )
icon = "< %=resource%>/icons/signal-none.png";
else if (q == 0)
icon = "< %=resource%>/icons/signal-0.png";
else if (q < 25 )
icon = "< %=resource%>/icons/signal-0-25.png";
else if (q < 50 )
icon = "< %=resource%>/icons/signal-25-50.png";
else if (q < 75 )
icon = "< %=resource%>/icons/signal-50-75.png";
else
icon = "< %=resource%>/icons/signal-75-100.png";
if (!devup[wifidevs[iw.id]])
devup[wifidevs[iw.id]] = is_assoc;
var sig = document.getElementById(iw.id + '-iw-signal');
if (sig)
sig.innerHTML = String.format(
'< span class = "ifacebadge" title = "<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%>" > < img src = "%s" / > %d%%< / span > ',
iw.signal, iw.noise, icon, p
);
var toggle = document.getElementById(iw.id + '-iw-toggle');
if (toggle)
{
if (!iw.disabled)
{
toggle.className = 'cbi-button cbi-button-reset';
toggle.value = '< %:Disable%>';
toggle.title = '< %:Shutdown this network%>';
}
else
{
toggle.className = 'cbi-button cbi-button-reload';
toggle.value = '< %:Enable%>';
toggle.title = '< %:Activate this network%>';
}
toggle.setAttribute('active', !iw.disabled);
}
var info = document.getElementById(iw.id + '-iw-status');
if (info)
{
if (is_assoc)
info.innerHTML = String.format(
'< strong > < %:SSID%>:< / strong > %h | ' +
'< strong > < %:Mode%>:< / strong > %s< br / > ' +
'< strong > < %:BSSID%>:< / strong > %s | ' +
'< strong > < %:Encryption%>:< / strong > %s',
iw.ssid, iw.mode, iw.bssid,
iw.encryption ? iw.encryption : '< %:None%>'
);
else
info.innerHTML = String.format(
'< strong > < %:SSID%>:< / strong > %h | ' +
'< strong > < %:Mode%>:< / strong > %s< br / > ' +
'< em > %s< / em > ',
iw.ssid || '?', iw.mode,
is_reconnecting
? '< em > < %:Wireless is restarting...%>< / em > '
: '< em > < %:Wireless is disabled or not associated%>< / em > '
);
}
var dev = document.getElementById(wifidevs[iw.id] + '-iw-devinfo');
if (dev)
{
if (is_assoc)
dev.innerHTML = String.format(
'< strong > < %:Channel%>:< / strong > %s (%s < %:GHz%>) | ' +
'< strong > < %:Bitrate%>:< / strong > %s < %:Mbit/s%>',
iw.channel ? iw.channel : '?',
iw.frequency ? iw.frequency : '?',
iw.bitrate ? iw.bitrate : '?'
);
else
dev.innerHTML = '';
}
if (assoctable)
{
var assoclist = [ ];
2018-05-31 13:44:12 +00:00
for (var bssid in iw.assoclist)
2018-01-23 14:36:03 +00:00
{
assoclist.push(iw.assoclist[bssid]);
assoclist[assoclist.length-1].bssid = bssid;
}
assoclist.sort(function(a, b) { a.bssid < b.bssid } ) ;
2018-05-31 13:44:12 +00:00
for (var j = 0; j < assoclist.length ; j + + )
2018-01-23 14:36:03 +00:00
{
var icon;
var q = (-1 * (assoclist[j].noise - assoclist[j].signal)) / 5;
if (q < 1 )
icon = "< %=resource%>/icons/signal-0.png";
else if (q < 2 )
icon = "< %=resource%>/icons/signal-0-25.png";
else if (q < 3 )
icon = "< %=resource%>/icons/signal-25-50.png";
else if (q < 4 )
icon = "< %=resource%>/icons/signal-50-75.png";
else
icon = "< %=resource%>/icons/signal-75-100.png";
2018-05-31 13:44:12 +00:00
var host = hosts[assoclist[j].bssid],
name = host ? (host.name || host.ipv4 || host.ipv6) : null,
hint = (host & & host.name & & (host.ipv4 || host.ipv6)) ? (host.ipv4 || host.ipv6) : null;
assoctable.appendChild(E('< div class = "tr cbi-section-table-row cbi-rowstyle-%d" > '.format(rowstyle), [
E('< div class = "td" > < span class = "ifacebadge" title = "%q" > < img src = "<%=resource%>/icons/wifi.png" / > %h< / span > < / div > '
.format(iw.device.name, iw.ifname)),
E('< div class = "td" style = "white-space:nowrap" > %h< / div > '
.format(iw.ssid || '?')),
E('< div class = "td" > %h< / div > '
.format(assoclist[j].bssid)),
E('< div class = "td" > ', hint ? '< div style = "max-width:200px;overflow:hidden;text-overflow:ellipsis" > %h (%h)< / div > '
.format(name || '?', hint) : (name || '?')),
E('< div class = "td" > < span class = "ifacebadge" title = "<%:Signal%>: %d <%:dBm%> / <%:Noise%>: %d <%:dBm%> / <%:SNR%>: %d" > < img src = "%s" / > %d / %d < %:dBm%>< / span > < / div > '
.format(assoclist[j].signal, assoclist[j].noise, assoclist[j].signal - assoclist[j].noise, icon, assoclist[j].signal, assoclist[j].noise)),
E('< div class = "td" > ', [
E('< span style = "white-space:nowrap" > ', wifirate(assoclist[j], true)),
E('< br / > '),
E('< span style = "white-space:nowrap" > ', wifirate(assoclist[j], false))
])
]));
2018-01-23 14:36:03 +00:00
rowstyle = (rowstyle == 1) ? 2 : 1;
}
}
}
2018-05-31 13:44:12 +00:00
if (assoctable & & assoctable.firstElementChild === assoctable.lastElementChild)
assoctable.appendChild(E('< div class = "tr cbi-section-table-row" > < div class = "td" > < em > < br / > < %:No information available%>< / em > < / div > < / div > '));
2018-01-23 14:36:03 +00:00
for (var dev in devup)
{
var img = document.getElementById(dev + '-iw-upstate');
if (img)
img.src = '< %=resource%>/icons/wifi_big' + (devup[dev] ? '' : '_disabled') + '.png';
}
}
}
);
//]]>< / script >
< h2 name = "content" > < %:Wireless Overview%>< / h2 >
< fieldset class = "cbi-section" style = "display:none" >
< legend > < %:Reconnecting interface%>< / legend >
< img src = "<%=resource%>/icons/loading.gif" alt = "<%:Loading%>" style = "vertical-align:middle" / >
< span id = "iw-rc-status" > < %:Waiting for changes to be applied...%>< / span >
< / fieldset >
< div class = "cbi-map" >
< % for _, dev in ipairs(devices) do local nets = dev:get_wifinets() %>
<!-- device <%=dev:name()%> -->
< fieldset class = "cbi-section" >
2018-05-31 13:44:12 +00:00
< div class = "table cbi-section-table" style = "margin:10px; empty-cells:hide" >
2018-01-23 14:36:03 +00:00
<!-- physical device -->
2018-05-31 13:44:12 +00:00
< div class = "tr" >
< div class = "td" >
< img src = "<%=resource%>/icons/wifi_big_disabled.png" id = "<%=dev:name()%>-iw-upstate" / >
< / div >
< div class = "td left" >
2018-01-23 14:36:03 +00:00
< big > < strong > < %=guess_wifi_hw(dev)%> (< %=dev:name()%>)< / strong > < / big > < br / >
< span id = "<%=dev:name()%>-iw-devinfo" > < / span >
2018-05-31 13:44:12 +00:00
< / div >
< div class = "td right" >
2018-01-23 14:36:03 +00:00
< form action = "<%=url('admin/network/wireless_join')%>" method = "post" class = "inline" >
< input type = "hidden" name = "device" value = "<%=dev:name()%>" / >
< input type = "hidden" name = "token" value = "<%=token%>" / >
< input type = "submit" class = "cbi-button cbi-button-find" style = "width:100px" title = "<%:Find and join network%>" value = "<%:Scan%>" / >
< / form >
< form action = "<%=url('admin/network/wireless_add')%>" method = "post" class = "inline" >
< input type = "hidden" name = "device" value = "<%=dev:name()%>" / >
< input type = "hidden" name = "token" value = "<%=token%>" / >
< input type = "submit" class = "cbi-button cbi-button-add" style = "width:100px" title = "<%:Provide new network%>" value = "<%:Add%>" / >
< / form >
2018-05-31 13:44:12 +00:00
< / div >
< / div >
2018-01-23 14:36:03 +00:00
<!-- /physical device -->
<!-- network list -->
< % if #nets > 0 then %>
< % for i, net in ipairs(nets) do %>
2018-05-31 13:44:12 +00:00
< div class = "tr cbi-section-table-row cbi-rowstyle-<%=1 + ((i-1) % 2)%>" >
< div class = "td" id = "<%=net:id()%>-iw-signal" >
2018-01-23 14:36:03 +00:00
< span class = "ifacebadge" title = "<%:Not associated%>" > < img src = "<%=resource%>/icons/signal-none.png" / > 0%< / span >
2018-05-31 13:44:12 +00:00
< / div >
< div class = "td left" id = "<%=net:id()%>-iw-status" >
2018-01-23 14:36:03 +00:00
< em > < %:Collecting data...%>< / em >
2018-05-31 13:44:12 +00:00
< / div >
< div class = "td right" >
2018-01-23 14:36:03 +00:00
< input id = "<%=net:id()%>-iw-toggle" type = "button" class = "cbi-button cbi-button-reload" style = "width:100px" onclick = "wifi_shutdown('<%=net:id()%>', this)" title = "<%:Delete this network%>" value = "<%:Enable%>" / >
< input type = "button" class = "cbi-button cbi-button-edit" style = "width:100px" onclick = "location.href='<%=net:adminlink()%>'" title = "<%:Edit this network%>" value = "<%:Edit%>" / >
< input type = "button" class = "cbi-button cbi-button-remove" style = "width:100px" onclick = "wifi_delete('<%=net:id()%>')" title = "<%:Delete this network%>" value = "<%:Remove%>" / >
2018-05-31 13:44:12 +00:00
< / div >
< / div >
2018-01-23 14:36:03 +00:00
< % end %>
< % else %>
2018-05-31 13:44:12 +00:00
< div class = "tr cbi-section-table-row cbi-rowstyle-2" >
< div class = "td left" >
2018-01-23 14:36:03 +00:00
< em > < %:No network configured on this device%>< / em >
2018-05-31 13:44:12 +00:00
< / div >
< / div >
2018-01-23 14:36:03 +00:00
< % end %>
<!-- /network list -->
2018-05-31 13:44:12 +00:00
< / div >
2018-01-23 14:36:03 +00:00
< / fieldset >
<!-- /device <%=dev:name()%> -->
< % end %>
< h2 > < %:Associated Stations%>< / h2 >
< fieldset class = "cbi-section" >
2018-05-31 13:44:12 +00:00
< div class = "table cbi-section-table valign-middle" style = "margin:10px" id = "iw-assoclist" >
< div class = "tr cbi-section-table-titles" >
< div class = "th cbi-section-table-cell" > < / div >
< div class = "th cbi-section-table-cell" > < %:SSID%>< / div >
< div class = "th cbi-section-table-cell" > < %:MAC-Address%>< / div >
< div class = "th cbi-section-table-cell" > < %:Host%>< / div >
< div class = "th cbi-section-table-cell" > < %:Signal%> / < %:Noise%>< / div >
< div class = "th cbi-section-table-cell" > < %:RX Rate%> / < %:TX Rate%>< / div >
< / div >
< div class = "tr cbi-section-table-row cbi-rowstyle-2" >
< div class = "td" >
2018-01-23 14:36:03 +00:00
< em > < %:Collecting data...%>< / em >
2018-05-31 13:44:12 +00:00
< / div >
< / div >
< / div >
2018-01-23 14:36:03 +00:00
< / fieldset >
< / div >
< %+footer%>