summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--applications/luci-app-adblock/po/it/adblock.po2
-rw-r--r--applications/luci-app-adblock/po/ja/adblock.po2
-rw-r--r--applications/luci-app-adblock/po/pt-br/adblock.po2
-rw-r--r--applications/luci-app-adblock/po/ru/adblock.po2
-rw-r--r--applications/luci-app-adblock/po/sv/adblock.po2
-rw-r--r--applications/luci-app-adblock/po/templates/adblock.pot2
-rw-r--r--applications/luci-app-adblock/po/zh-cn/adblock.po2
-rw-r--r--applications/luci-app-adblock/po/zh-tw/adblock.po2
-rwxr-xr-xapplications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade1
-rw-r--r--applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js14
-rw-r--r--applications/luci-app-firewall/luasrc/view/firewall/cbi_addrule.htm7
-rw-r--r--applications/luci-app-firewall/luasrc/view/firewall/cbi_addsnat.htm5
-rw-r--r--applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua2
-rw-r--r--applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm49
-rw-r--r--applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm93
-rw-r--r--applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua2
-rw-r--r--applications/luci-app-olsr/luasrc/controller/olsr.lua42
-rw-r--r--applications/luci-app-splash/luasrc/controller/splash/splash.lua66
-rw-r--r--applications/luci-app-splash/luasrc/view/admin_status/splash.htm65
-rw-r--r--applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua100
-rw-r--r--applications/luci-app-travelmate/Makefile4
-rw-r--r--applications/luci-app-travelmate/luasrc/controller/travelmate.lua4
-rw-r--r--applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua15
-rw-r--r--applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm62
-rw-r--r--applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm1
-rw-r--r--applications/luci-app-travelmate/po/ja/travelmate.po67
-rw-r--r--applications/luci-app-travelmate/po/pt-br/travelmate.po49
-rw-r--r--applications/luci-app-travelmate/po/ru/travelmate.po87
-rw-r--r--applications/luci-app-travelmate/po/templates/travelmate.pot49
-rw-r--r--applications/luci-app-wol/luasrc/model/cbi/wol.lua8
-rw-r--r--contrib/package/community-profiles/files/etc/config/profile_potsdam2
-rw-r--r--documentation/api/modules/luci.http.protocol.html4
-rw-r--r--documentation/api/modules/luci.ip.cidr.html330
-rw-r--r--documentation/api/modules/luci.ip.html288
-rw-r--r--documentation/api/modules/luci.util.html2
-rw-r--r--documentation/api/modules/nixio.README.html6
-rw-r--r--documentation/api/modules/nixio.UnifiedIO.html10
-rw-r--r--libs/luci-lib-ip/src/ip.c531
-rw-r--r--libs/luci-lib-ip/src/ip.luadoc343
-rw-r--r--libs/luci-lib-nixio/docsrc/README.lua6
-rw-r--r--libs/luci-lib-nixio/docsrc/nixio.Socket.lua4
-rw-r--r--libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua28
-rw-r--r--libs/luci-lib-nixio/docsrc/nixio.fs.lua4
-rw-r--r--libs/luci-lib-nixio/docsrc/nixio.lua6
-rw-r--r--modules/luci-base/luasrc/cbi/datatypes.lua18
-rw-r--r--modules/luci-base/luasrc/http/protocol.luadoc4
-rw-r--r--modules/luci-base/luasrc/model/network.lua13
-rw-r--r--modules/luci-base/luasrc/sys.lua23
-rw-r--r--modules/luci-base/luasrc/tools/status.lua15
-rw-r--r--modules/luci-base/luasrc/util.luadoc4
-rw-r--r--modules/luci-base/luasrc/view/cbi/browser.htm1
-rw-r--r--modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm128
-rw-r--r--modules/luci-mod-admin-full/luasrc/controller/admin/network.lua1
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua9
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua9
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua51
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm2
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_system/flashops.htm3
-rw-r--r--modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua11
59 files changed, 1855 insertions, 809 deletions
diff --git a/applications/luci-app-adblock/po/it/adblock.po b/applications/luci-app-adblock/po/it/adblock.po
index bdaa2f29a..88adcc892 100644
--- a/applications/luci-app-adblock/po/it/adblock.po
+++ b/applications/luci-app-adblock/po/it/adblock.po
@@ -275,7 +275,7 @@ msgid ""
msgstr ""
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads & list processing in parallel "
"(default '4').<br />"
msgstr ""
diff --git a/applications/luci-app-adblock/po/ja/adblock.po b/applications/luci-app-adblock/po/ja/adblock.po
index d3a0a5c82..60c5a9a54 100644
--- a/applications/luci-app-adblock/po/ja/adblock.po
+++ b/applications/luci-app-adblock/po/ja/adblock.po
@@ -301,7 +301,7 @@ msgstr ""
"処理エラーまたはドメイン カウントが0以下の場合、メールを送信します。<br />"
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
"ダウンロードの制御とリストの処理を同時並行的に行うダウンロード キューのサイズ"
diff --git a/applications/luci-app-adblock/po/pt-br/adblock.po b/applications/luci-app-adblock/po/pt-br/adblock.po
index f264ed677..7eb6e3ebc 100644
--- a/applications/luci-app-adblock/po/pt-br/adblock.po
+++ b/applications/luci-app-adblock/po/pt-br/adblock.po
@@ -267,7 +267,7 @@ msgid ""
msgstr ""
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
diff --git a/applications/luci-app-adblock/po/ru/adblock.po b/applications/luci-app-adblock/po/ru/adblock.po
index 0898213a4..6e80e80b3 100644
--- a/applications/luci-app-adblock/po/ru/adblock.po
+++ b/applications/luci-app-adblock/po/ru/adblock.po
@@ -303,7 +303,7 @@ msgstr ""
"&le; 0.<br />"
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
"Значение очереди загрузки для выполнения параллельных загрузок (по умолчанию "
diff --git a/applications/luci-app-adblock/po/sv/adblock.po b/applications/luci-app-adblock/po/sv/adblock.po
index 5a86d2c92..d875a69f9 100644
--- a/applications/luci-app-adblock/po/sv/adblock.po
+++ b/applications/luci-app-adblock/po/sv/adblock.po
@@ -256,7 +256,7 @@ msgid ""
msgstr ""
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
diff --git a/applications/luci-app-adblock/po/templates/adblock.pot b/applications/luci-app-adblock/po/templates/adblock.pot
index 285bb1dca..5a93f8f07 100644
--- a/applications/luci-app-adblock/po/templates/adblock.pot
+++ b/applications/luci-app-adblock/po/templates/adblock.pot
@@ -248,7 +248,7 @@ msgid ""
msgstr ""
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
diff --git a/applications/luci-app-adblock/po/zh-cn/adblock.po b/applications/luci-app-adblock/po/zh-cn/adblock.po
index 3b8a35b04..1d7dc2b19 100644
--- a/applications/luci-app-adblock/po/zh-cn/adblock.po
+++ b/applications/luci-app-adblock/po/zh-cn/adblock.po
@@ -266,7 +266,7 @@ msgid ""
msgstr ""
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
diff --git a/applications/luci-app-adblock/po/zh-tw/adblock.po b/applications/luci-app-adblock/po/zh-tw/adblock.po
index 0d1536ba8..da00842d5 100644
--- a/applications/luci-app-adblock/po/zh-tw/adblock.po
+++ b/applications/luci-app-adblock/po/zh-tw/adblock.po
@@ -266,7 +266,7 @@ msgid ""
msgstr ""
msgid ""
-"Size of the download queue to handle downloads & list processing in parallel "
+"Size of the download queue to handle downloads &amp; list processing in parallel "
"(default '4').<br />"
msgstr ""
diff --git a/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade b/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade
index 832744f7d..1b890c0cb 100755
--- a/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade
+++ b/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade
@@ -2,5 +2,6 @@
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/
/etc/init.d/uhttpd restart
+/etc/init.d/rpcd reload
return 0
diff --git a/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js b/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js
index c2fe81d58..604074ad3 100644
--- a/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js
+++ b/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js
@@ -128,7 +128,7 @@ function ubus_call(command, argument, params, variable) {
}
}
} else {
- error_box("<b>Ubus call faild:</b></br>Request: " + request_json + "</br>Response: " + JSON.stringify(response))
+ error_box("<b>Ubus call faild:</b><br />Request: " + request_json + "<br />Response: " + JSON.stringify(response))
}
ubus_closed++;
}
@@ -180,7 +180,7 @@ function upgrade_check_callback(request_text) {
if(request_json.upgrades != undefined) {
info_output += "<h3>Package upgrades available</h3>"
for (upgrade in request_json.upgrades) {
- info_output += "<b>" + upgrade + "</b>: " + request_json.upgrades[upgrade][1] + " to " + request_json.upgrades[upgrade][0] + "</br>"
+ info_output += "<b>" + upgrade + "</b>: " + request_json.upgrades[upgrade][1] + " to " + request_json.upgrades[upgrade][0] + "<br />"
}
}
data.packages = request_json.packages
@@ -231,9 +231,9 @@ function upgrade_request_callback(request) {
var filename_split = data.sysupgrade_url.split("/")
data.filename = filename_split[filename_split.length - 1]
- info_output = "Firmware created</br><b>" + data.filename + "</b>"
+ info_output = 'Firmware created: <a href="' + data.sysupgrade_url + '"><b>' + data.filename + '</b></a>'
if(data.advanced_mode == 1) {
- info_output += '</br><a target="_blank" href="' + data.sysupgrade_url + '.log">Build log</a>'
+ info_output += '<br /><a target="_blank" href="' + data.sysupgrade_url + '.log">Build log</a>'
}
info_box(info_output);
@@ -373,12 +373,12 @@ function server_request(request_dict, path, callback) {
error_box("No firmware created due to image size. Try again with less packages selected.")
} else if (request.status === 422) {
- error_box("Unknown package in request")
-
+ var package_missing = response.getResponseHeader("X-Unknown-Package");
+ error_box("Unknown package in request: <b>" + package_missing + "</b>")
} else if (request.status === 500) {
request_json = JSON.parse(request_text)
- error_box_content = "<b>Internal server error</b></br>"
+ error_box_content = "<b>Internal server error</b><br />"
error_box_content += request_json.error
if(request_json.log != undefined) {
data.log_url = request_json.log
diff --git a/applications/luci-app-firewall/luasrc/view/firewall/cbi_addrule.htm b/applications/luci-app-firewall/luasrc/view/firewall/cbi_addrule.htm
index 58121c420..b06fac3de 100644
--- a/applications/luci-app-firewall/luasrc/view/firewall/cbi_addrule.htm
+++ b/applications/luci-app-firewall/luasrc/view/firewall/cbi_addrule.htm
@@ -2,6 +2,7 @@
local fw = require "luci.model.firewall".init()
local wz = fw:get_zone("wan")
local lz = fw:get_zone("lan")
+ local zones = fw:get_zones()
%>
<div class="cbi-section-create cbi-tblsection-create">
@@ -38,7 +39,7 @@
</tr>
</table>
<% end %>
- <% if wz and lz then %>
+ <% if #zones > 1 then %>
<table class="cbi-section-table" style="margin-left:5px">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell left" colspan="6"><br /><%:New forward rule%>:</th>
@@ -56,14 +57,14 @@
<td class="cbi-section-table-cell" style="width:110px">
<select class="cbi-input-text" id="_newfwd.src" name="_newfwd.src">
<% local k, v; for k, v in ipairs(fw:get_zones()) do -%>
- <option<%=ifattr(v:name() == "lan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
+ <option<%=ifattr(v:name() == "wan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
<%- end %>
</select>
</td>
<td class="cbi-section-table-cell" style="width:110px">
<select class="cbi-input-text" id="_newfwd.dest" name="_newfwd.dest">
<% local k, v; for k, v in ipairs(fw:get_zones()) do -%>
- <option<%=ifattr(v:name() == "wan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
+ <option<%=ifattr(v:name() == "lan", "selected", "selected")%> value="<%=v:name()%>"><%=v:name()%></option>
<%- end %>
</select>
</td>
diff --git a/applications/luci-app-firewall/luasrc/view/firewall/cbi_addsnat.htm b/applications/luci-app-firewall/luasrc/view/firewall/cbi_addsnat.htm
index ce275111d..0a5913fc0 100644
--- a/applications/luci-app-firewall/luasrc/view/firewall/cbi_addsnat.htm
+++ b/applications/luci-app-firewall/luasrc/view/firewall/cbi_addsnat.htm
@@ -1,8 +1,7 @@
<%
local fw = require "luci.model.firewall".init()
local nw = require "luci.model.network".init()
- local wz = fw:get_zone("wan")
- local lz = fw:get_zone("lan")
+ local zones = fw:get_zones()
local keys, vals, a, k, v = {}, {}
for k, v in ipairs(nw:get_interfaces()) do
@@ -14,7 +13,7 @@
%>
<div class="cbi-section-create cbi-tblsection-create">
- <% if wz and lz then %>
+ <% if #zones > 1 then %>
<br />
<table class="cbi-section-table" style="width:700px; margin-left:5px">
<tr class="cbi-section-table-titles">
diff --git a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua
index 920dc6afb..4b1a070d1 100644
--- a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua
+++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua
@@ -93,7 +93,7 @@ function configCheck()
local trackingNumber = uci:get("mwan3", iface, "track_ip")
overview[iface]["tracking"] = 0
- if #trackingNumber > 0 then
+ if trackingNumber and #trackingNumber > 0 then
overview[iface]["tracking"] = #trackingNumber
overview[iface]["reliability"] = false
local reliabilityNumber = tonumber(uci:get("mwan3", iface, "reliability"))
diff --git a/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm b/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm
index 6dc3d1274..86b5ac696 100644
--- a/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm
+++ b/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm
@@ -15,30 +15,27 @@ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_
for ( var iface in status.interfaces)
{
var state = '';
- var css = '';
switch (status.interfaces[iface].status)
{
case 'online':
state = '<%:Online (tracking active)%>';
- css = 'wanon';
break;
case 'notMonitored':
state = '<%:Online (tracking off)%>';
- css = 'wanon';
break;
case 'offline':
state = '<%:Offline%>';
- css = 'wanoff';
break;
default:
state = '<%:Disabled%>';
- css = 'wanoff';
break;
}
statusview += String.format(
- '<span class="%s"><strong>%s</strong><br />%s</span>',
- css,
- iface,
+ '<div><strong>Interface: </strong>%s</div>',
+ iface
+ );
+ statusview += String.format(
+ '<div><strong>Status: </strong>%s</div></br></br>',
state
);
}
@@ -53,36 +50,8 @@ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_
//]]></script>
<fieldset id="interface_field" class="cbi-section">
- <legend><%:MWAN Interface Live Status%></legend>
- <div id="mwan_status_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
+ <legend><%:MWAN Interfaces%></legend>
+ <div id="mwan_status_text">
+ <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%>
+ </div>
</fieldset>
-
-<style type="text/css">
- .container { /* container for entire page. fixes bootstrap theme's ridiculously small page width */
- max-width: 1044px;
- }
- #mwan_status_text {
- display: table;
- font-size: 14px;
- margin: auto;
- max-width: 1044px;
- min-width: 246px;
- width: 100%;
- }
- .wanon {
- background-color: rgb(144, 240, 144);
- }
- .wanoff {
- background-color: rgb(240, 144, 144);
- }
- .wanon, .wanoff {
- border-radius: 60px;
- box-shadow: 0px 2px 5px -3px;
- float: left;
- margin: 8px 3px 0px 3px;
- min-height: 30px;
- min-width: 235px;
- padding: 5px 10px 8px 10px;
- text-align: center;
- }
-</style>
diff --git a/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm b/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm
index 21e59a801..cb476967f 100644
--- a/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm
+++ b/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm
@@ -14,98 +14,7 @@
</ul>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
-<script type="text/javascript">//<![CDATA[
- XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null,
- function(x, status)
- {
- var legend = document.getElementById('diag-rc-legend');
- var statusDiv = document.getElementById('diag-rc-output');
- legend.style.display = 'none';
- if (status.interfaces)
- {
- var statusview = '';
- for ( var iface in status.interfaces)
- {
- var state = '';
- var css = '';
- switch (status.interfaces[iface].status)
- {
- case 'online':
- state = '<%:Online (tracking active)%>';
- css = 'wanon';
- break;
- case 'notMonitored':
- state = '<%:Online (tracking off)%>';
- css = 'wanon';
- break;
- case 'offline':
- state = '<%:Offline%>';
- css = 'wanoff';
- break;
- default:
- state = '<%:Disabled%>';
- css = 'wanoff';
- break;
- }
- statusview += String.format(
- '<span class="%s"><strong>%s</strong><br />%s</span>',
- css,
- iface,
- state
- );
- }
- statusDiv.innerHTML = statusview;
- }
- else
- {
- statusDiv.innerHTML = '<strong><%:No MWAN interfaces found%></strong>';
- }
- }
- );
-//]]></script>
-<div class="cbi-map">
- <h2 name="content"><%:MWAN Status - Interface%></h2>
- <%if not require("luci.sys").init.enabled("mwan3") then%>
- <div><strong><%:INFO: MWAN not running%></strong></div>
- <%end%>
- <fieldset class="cbi-section">
- <legend id="diag-rc-legend"><%:Collecting data...%></legend>
- <span id="diag-rc-output">
- <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />
- </span>
- </fieldset>
-</div>
-
-<style type="text/css">
- #mwan_status_text {
- display: table;
- font-size: 14px;
- margin: auto;
- max-width: 1044px;
- min-width: 246px;
- width: 100%;
- }
- .wanon {
- background-color: rgb(144, 240, 144);
- }
- .wanoff {
- background-color: rgb(240, 144, 144);
- }
- .wanon, .wanoff {
- border-radius: 60px;
- box-shadow: 0px 2px 5px -3px;
- float: left;
- margin: 8px 3px 0px 3px;
- min-height: 30px;
- min-width: 235px;
- padding: 5px 10px 8px 10px;
- text-align: center;
- }
- #mwan_statuslog_text {
- padding: 20px;
- text-align: left;
- }
-</style>
+<%+mwan/overview_status_interface%>
<%+footer%>
diff --git a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
index 74edaf489..396dedd4a 100644
--- a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
+++ b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
@@ -86,7 +86,7 @@ pip.default = "1"
local compr = s:taboption("general", Flag, "compression", translate("Enable compression"),
translate("Enable compression"))
-compr.default = "1"
+compr.default = "0"
local udp = s:taboption("general", Flag, "udp", translate("Enable UDP"),
translate("Enable UDP channel support; this must be enabled unless you know what you are doing"))
diff --git a/applications/luci-app-olsr/luasrc/controller/olsr.lua b/applications/luci-app-olsr/luasrc/controller/olsr.lua
index 0564bd4ea..229f3d61b 100644
--- a/applications/luci-app-olsr/luasrc/controller/olsr.lua
+++ b/applications/luci-app-olsr/luasrc/controller/olsr.lua
@@ -101,41 +101,19 @@ end
local function local_mac_lookup(ipaddr)
- local _, ifa, dev
-
- ipaddr = tostring(ipaddr)
-
- if not ifaddr_table then
- ifaddr_table = nixio.getifaddrs()
- end
-
- -- ipaddr -> ifname
- for _, ifa in ipairs(ifaddr_table) do
- if ifa.addr == ipaddr then
- dev = ifa.name
- break
- end
- end
-
- -- ifname -> macaddr
- for _, ifa in ipairs(ifaddr_table) do
- if ifa.name == dev and ifa.family == "packet" then
- return ifa.addr
- end
+ local _, rt
+ for _, rt in ipairs(luci.ip.routes({ type = 1, src = ipaddr })) do
+ local link = rt.dev and luci.ip.link(rt.dev)
+ local mac = link and luci.ip.checkmac(link.mac)
+ if mac then return mac end
end
end
local function remote_mac_lookup(ipaddr)
local _, n
-
- if not neigh_table then
- neigh_table = luci.ip.neighbors()
- end
-
- for _, n in ipairs(neigh_table) do
- if n.mac and n.dest and n.dest:equal(ipaddr) then
- return n.mac
- end
+ for _, n in ipairs(luci.ip.neighbors({ dest = ipaddr })) do
+ local mac = luci.ip.checkmac(n.mac)
+ if mac then return mac end
end
end
@@ -201,9 +179,9 @@ function action_neigh(json)
for _, val in ipairs(assoclist) do
if val.network == interface and val.list then
+ local assocmac, assot
for assocmac, assot in pairs(val.list) do
- assocmac = string.lower(assocmac or "")
- if rmac == assocmac then
+ if rmac == luci.ip.checkmac(assocmac) then
signal = tonumber(assot.signal)
noise = tonumber(assot.noise)
snr = (noise*-1) - (signal*-1)
diff --git a/applications/luci-app-splash/luasrc/controller/splash/splash.lua b/applications/luci-app-splash/luasrc/controller/splash/splash.lua
index 13b8edce6..b4fdbd53a 100644
--- a/applications/luci-app-splash/luasrc/controller/splash/splash.lua
+++ b/applications/luci-app-splash/luasrc/controller/splash/splash.lua
@@ -2,6 +2,7 @@ module("luci.controller.splash.splash", package.seeall)
local uci = luci.model.uci.cursor()
local util = require "luci.util"
+local ipc = require "luci.ip"
function index()
entry({"admin", "services", "splash"}, cbi("splash/splash"), _("Client-Splash"), 90)
@@ -24,30 +25,35 @@ function index()
end
function ip_to_mac(ip)
- local ipc = require "luci.ip"
local i, n
-
- for i, n in ipairs(ipc.neighbors()) do
- if n.mac and n.dest and n.dest:equal(ip) then
- return n.mac
- end
+ for i, n in ipairs(ipc.neighbors({ dest = ip })) do
+ local mac = ipc.checkmac(n.mac)
+ if mac then return mac end
end
end
function action_dispatch()
local uci = luci.model.uci.cursor_state()
- local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR")) or ""
+ local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR"))
local access = false
- uci:foreach("luci_splash", "lease", function(s)
- if s.mac and s.mac:lower() == mac then access = true end
- end)
+ if mac then
+ uci:foreach("luci_splash", "lease", function(s)
+ if ipc.checkmac(s.mac) == mac then
+ access = true
+ return false
+ end
+ end)
- uci:foreach("luci_splash", "whitelist", function(s)
- if s.mac and s.mac:lower() == mac then access = true end
- end)
+ uci:foreach("luci_splash", "whitelist", function(s)
+ if ipc.checkmac(s.mac) == mac then
+ access = true
+ return false
+ end
+ end)
+ end
- if #mac > 0 and access then
+ if access then
luci.http.redirect(luci.dispatcher.build_url())
else
luci.http.redirect(luci.dispatcher.build_url("splash", "splash"))
@@ -56,33 +62,39 @@ end
function blacklist()
leased_macs = { }
- uci:foreach("luci_splash", "blacklist",
- function(s) leased_macs[s.mac:lower()] = true
+ uci:foreach("luci_splash", "blacklist", function(s)
+ local m = ipc.checkmac(s.mac)
+ if m then leased_macs[m] = true end
end)
return leased_macs
end
function action_activate()
local ipc = require "luci.ip"
- local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR") or "127.0.0.1") or ""
+ local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR") or "127.0.0.1")
local uci_state = require "luci.model.uci".cursor_state()
local blacklisted = false
if mac and luci.http.formvalue("accept") then
- uci:foreach("luci_splash", "blacklist",
- function(s) if s.mac and s.mac:lower() == mac then blacklisted = true end
+ uci:foreach("luci_splash", "blacklist", function(s)
+ if ipc.checkmac(s.mac) == mac then
+ blacklisted = true
+ return false
+ end
end)
+
if blacklisted then
luci.http.redirect(luci.dispatcher.build_url("splash" ,"blocked"))
else
+ local id = tostring(mac):gsub(':', ''):lower()
local redirect_url = uci:get("luci_splash", "general", "redirect_url")
if not redirect_url then
- redirect_url = uci_state:get("luci_splash_locations", mac:gsub(':', ''):lower(), "location")
+ redirect_url = uci_state:get("luci_splash_locations", id, "location")
end
if not redirect_url then
redirect_url = luci.model.uci.cursor():get("freifunk", "community", "homepage") or 'http://www.freifunk.net'
end
- remove_redirect(mac:gsub(':', ''):lower())
- os.execute("luci-splash lease "..mac.." >/dev/null 2>&1")
+ remove_redirect(id)
+ os.execute("luci-splash lease "..tostring(mac).." >/dev/null 2>&1")
luci.http.redirect(redirect_url)
end
else
@@ -101,6 +113,7 @@ function action_status_admin()
remove = { }
}
+ local key, _
for key, _ in pairs(macs) do
local policy = luci.http.formvalue("policy.%s" % key)
local mac = luci.http.protocol.urldecode(key)
@@ -141,17 +154,17 @@ function action_status_public()
luci.template.render("admin_status/splash", { is_admin = false })
end
-function remove_redirect(mac)
- local mac = mac:lower()
- mac = mac:gsub(":", "")
+function remove_redirect(id)
local uci = require "luci.model.uci".cursor_state()
local redirects = uci:get_all("luci_splash_locations")
--uci:load("luci_splash_locations")
uci:revert("luci_splash_locations")
+
-- For all redirects
+ local k, v
for k, v in pairs(redirects) do
if v[".type"] == "redirect" then
- if v[".name"] ~= mac then
+ if v[".name"] ~= id then
-- Rewrite state
uci:section("luci_splash_locations", "redirect", v[".name"], {
location = v.location
@@ -159,5 +172,6 @@ function remove_redirect(mac)
end
end
end
+
uci:save("luci_splash_redirects")
end
diff --git a/applications/luci-app-splash/luasrc/view/admin_status/splash.htm b/applications/luci-app-splash/luasrc/view/admin_status/splash.htm
index 3415c205d..37f67776a 100644
--- a/applications/luci-app-splash/luasrc/view/admin_status/splash.htm
+++ b/applications/luci-app-splash/luasrc/view/admin_status/splash.htm
@@ -6,6 +6,8 @@
<%-
local utl = require "luci.util"
+local sys = require "luci.sys"
+local ipc = require "luci.ip"
local ipt = require "luci.sys.iptparser".IptParser()
local uci = require "luci.model.uci".cursor_state()
local wat = require "luci.tools.webadmin"
@@ -14,21 +16,15 @@ local fs = require "nixio.fs"
local clients = { }
local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime") or 1) * 60 * 60
-local leasefile = "/tmp/dhcp.leases"
-
-uci:foreach("dhcp", "dnsmasq",
- function(s)
- if s.leasefile then leasefile = s.leasefile end
- end)
-
uci:foreach("luci_splash_leases", "lease",
function(s)
- if s.start and s.mac then
- clients[s.mac:lower()] = {
+ local m = ipc.checkmac(s.mac)
+ if m and s.start then
+ clients[m] = {
start = tonumber(s.start),
limit = ( tonumber(s.start) + leasetime ),
- mac = s.mac:upper(),
+ mac = m,
ipaddr = s.ipaddr,
policy = "normal",
packets = 0,
@@ -39,11 +35,12 @@ uci:foreach("luci_splash_leases", "lease",
for _, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases"})) do
if r.options and #r.options >= 2 and r.options[1] == "MAC" then
- if not clients[r.options[2]:lower()] then
- clients[r.options[2]:lower()] = {
+ local m = ipc.checkmac(r.options[2])
+ if m and not clients[m] then
+ clients[m] = {
start = 0,
limit = 0,
- mac = r.options[2]:upper(),
+ mac = m,
policy = ( r.target == "RETURN" ) and "whitelist" or "blacklist",
packets = 0,
bytes = 0
@@ -60,7 +57,7 @@ for mac, client in pairs(clients) do
if client.ipaddr then
local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=client.ipaddr})
- local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", client.mac:upper()}})
+ local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", client.mac}})
if rin and #rin > 0 then
client.bytes_in = rin[1].bytes
@@ -76,39 +73,27 @@ end
uci:foreach("luci_splash", "whitelist",
function(s)
- if s.mac and clients[s.mac:lower()] then
- clients[s.mac:lower()].policy="whitelist"
+ local m = ipc.checkmac(s.mac)
+ if m and clients[m] then
+ clients[m].policy="whitelist"
end
end)
uci:foreach("luci_splash", "blacklist",
function(s)
- if s.mac and clients[s.mac:lower()] then
- clients[s.mac:lower()].policy=(s.kicked and "kicked" or "blacklist")
+ local m = ipc.checkmac(s.mac)
+ if m and clients[m] then
+ clients[m].policy=(s.kicked and "kicked" or "blacklist")
end
end)
-if fs.access(leasefile) then
- for l in io.lines(leasefile) do
- local time, mac, ip, name = l:match("^(%d+) (%S+) (%S+) (%S+)")
- if time and mac and ip then
- local c = clients[mac:lower()]
- if c then
- c.ip = ip
- c.hostname = ( name ~= "*" ) and name or nil
- end
- end
+sys.net.host_hints(function(mac, v4, v6, name)
+ local c = mac and clients[mac]
+ if c then
+ c.ip = c.ip or v4
+ c.hostname = c.hostname or name
end
-end
-
-for i, n in ipairs(ipc.neighbors({ family = 4 })) do
- if n.mac and n.dest then
- local c = clients[n.mac]
- if c and not c.ip then
- c.ip = n.dest:string()
- end
- end
-end
+end)
local function showmac(mac)
if not is_admin then
@@ -176,7 +161,7 @@ end
splash.hostname, splash.ip, splash.mac, splash.timeleft, splash.trafficin, splash.trafficout);
<% if is_admin then %>
- s += String.format('<select name="policy.%s" style="width:200px">', splash.mac.toLowerCase());
+ s += String.format('<select name="policy.%s" style="width:200px">', splash.mac);
if (splash.policy == 'whitelist') {
s += '<option value="whitelist" selected="selected"><%:whitelisted%></option>'
} else {
@@ -196,7 +181,7 @@ end
s += String.format(
'</select>' +
'<input type="submit" class="cbi-button cbi-button-save" name="save.%s" value="<%:Save%>" />',
- splash.mac.toLowerCase());
+ splash.mac);
<% else %>
s += String.format('%s', splash.policy);
<% end %>
diff --git a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua
index 2a8aceec0..9f7a51a86 100644
--- a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua
+++ b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua
@@ -3,25 +3,80 @@
module("luci.statistics.rrdtool.definitions.apcups",package.seeall)
-function rrdargs( graph, plugin, plugin_instance, dtype )
+function rrdargs( graph, plugin, plugin_instance )
+
+ local lu = require("luci.util")
+ local rv = { }
+
+ -- Types and instances supported by APC UPS
+ -- e.g. ups_types -> { 'timeleft', 'charge', 'percent', 'voltage' }
+ -- e.g. ups_inst['voltage'] -> { 'input', 'battery' }
+
+ local ups_types = graph.tree:data_types( plugin, plugin_instance )
+
+ local ups_inst = {}
+ for _, t in ipairs(ups_types) do
+ ups_inst[t] = graph.tree:data_instances( plugin, plugin_instance, t )
+ end
+
+
+ -- Check if hash table or array is empty or nil-filled
+
+ local function empty( t )
+ for _, v in pairs(t) do
+ if type(v) then return false end
+ end
+ return true
+ end
+
+
+ -- Append graph definition but only types/instances which are
+ -- supported and available to the plugin and UPS.
+
+ local function add_supported( t, defs )
+ local def_inst = defs['data']['instances']
+
+ if type(def_inst) == "table" then
+ for k, v in pairs( def_inst ) do
+ if lu.contains( ups_types, k) then
+ for j = #v, 1, -1 do
+ if not lu.contains( ups_inst[k], v[j] ) then
+ table.remove( v, j )
+ end
+ end
+ if #v == 0 then
+ def_inst[k] = nil -- can't assign v: immutable
+ end
+ else
+ def_inst[k] = nil -- can't assign v: immutable
+ end
+ end
+ if empty(def_inst) then return end
+ end
+ table.insert( t, defs )
+ end
+
+
+ -- Graph definitions for APC UPS measurements MUST use only 'instances':
+ -- e.g. instances = { voltage = { "input", "output" } }
local voltagesdc = {
title = "%H: Voltages on APC UPS - Battery",
vlabel = "Volts DC",
- alt_autoscale = true,
+ alt_autoscale = true,
number_format = "%5.1lfV",
data = {
instances = {
voltage = { "battery" }
},
-
- options = {
+ options = {
voltage = { title = "Battery voltage", noarea=true }
}
}
}
-
- local voltages = {
+ add_supported( rv, voltagesdc )
+
+ local voltagesac = {
title = "%H: Voltages on APC UPS - AC",
vlabel = "Volts AC",
alt_autoscale = true,
@@ -30,13 +85,13 @@ function rrdargs( graph, plugin, plugin_instance, dtype )
instances = {
voltage = { "input", "output" }
},
-
options = {
voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true },
voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true }
}
}
}
+ add_supported( rv, voltagesac )
local percentload = {
title = "%H: Load on APC UPS ",
@@ -45,17 +100,15 @@ function rrdargs( graph, plugin, plugin_instance, dtype )
y_max = "100",
number_format = "%5.1lf%%",
data = {
- sources = {
- percent_load = { "value" }
- },
instances = {
- percent = "load"
+ percent = { "load" }
},
options = {
percent_load = { color = "00ff00", title = "Load level" }
}
}
}
+ add_supported( rv, percentload )
local charge_percent = {
title = "%H: Battery charge on APC UPS ",
@@ -64,54 +117,59 @@ function rrdargs( graph, plugin, plugin_instance, dtype )
y_max = "100",
number_format = "%5.1lf%%",
data = {
- types = { "charge" },
+ instances = {
+ charge = { "" }
+ },
options = {
charge = { color = "00ff0b", title = "Charge level" }
}
}
}
+ add_supported( rv, charge_percent )
local temperature = {
title = "%H: Battery temperature on APC UPS ",
vlabel = "\176C",
number_format = "%5.1lf\176C",
data = {
- types = { "temperature" },
+ instances = {
+ temperature = { "" }
+ },
options = {
temperature = { color = "ffb000", title = "Battery temperature" } }
}
}
+ add_supported( rv, temperature )
local timeleft = {
title = "%H: Time left on APC UPS ",
vlabel = "Minutes",
number_format = "%.1lfm",
data = {
- sources = {
- timeleft = { "value" }
+ instances = {
+ timeleft = { "" }
},
options = {
timeleft = { color = "0000ff", title = "Time left" }
}
}
}
+ add_supported( rv, timeleft )
local frequency = {
title = "%H: Incoming line frequency on APC UPS ",
vlabel = "Hz",
number_format = "%5.0lfhz",
data = {
- sources = {
- frequency_input = { "value" }
- },
instances = {
- frequency = "frequency"
+ frequency = { "input" }
},
options = {
- frequency_frequency = { color = "000fff", title = "Line frequency" }
+ frequency_input = { color = "000fff", title = "Line frequency" }
}
}
}
+ add_supported( rv, frequency )
- return { voltages, voltagesdc, percentload, charge_percent, temperature, timeleft, frequency }
+ return rv
end
diff --git a/applications/luci-app-travelmate/Makefile b/applications/luci-app-travelmate/Makefile
index 6170f9d4c..2bd25bc17 100644
--- a/applications/luci-app-travelmate/Makefile
+++ b/applications/luci-app-travelmate/Makefile
@@ -1,11 +1,11 @@
-# Copyright 2017 Dirk Brenken (dev@brenken.org)
+# Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the Apache License, Version 2.0
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for Travelmate
-LUCI_DEPENDS:=+travelmate +luci-lib-jsonc
+LUCI_DEPENDS:=+travelmate +luci-lib-jsonc +qrencode
LUCI_PKGARCH:=all
include ../../luci.mk
diff --git a/applications/luci-app-travelmate/luasrc/controller/travelmate.lua b/applications/luci-app-travelmate/luasrc/controller/travelmate.lua
index 0f7583497..14b8d77ff 100644
--- a/applications/luci-app-travelmate/luasrc/controller/travelmate.lua
+++ b/applications/luci-app-travelmate/luasrc/controller/travelmate.lua
@@ -3,7 +3,6 @@
module("luci.controller.travelmate", package.seeall)
-local fs = require("nixio.fs")
local util = require("luci.util")
local i18n = require("luci.i18n")
local templ = require("luci.template")
@@ -15,7 +14,8 @@ function index()
entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40).dependent = false
entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
entry({"admin", "services", "travelmate", "stations"}, template("travelmate/stations"), _("Wireless Stations"), 20).leaf = true
- entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 30).leaf = true
+ entry({"admin", "services", "travelmate", "apqr"}, template("travelmate/ap_qr"), _("AP QR-Codes"), 30).leaf = true
+ entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 40).leaf = true
entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100)
entry({"admin", "services", "travelmate", "advanced", "configuration"}, cbi("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true
entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, cbi("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true
diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua
index 4fec920f7..e68786615 100644
--- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua
+++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua
@@ -181,28 +181,27 @@ e2.datatype = "and(uciname,rangelength(6,6))"
e2.rmempty = true
e3 = e:option(Value, "trm_maxretry", translate("Connection Limit"),
- translate("Retry limit to connect to an uplink. ")
- .. translate("To disable this feature set it to '0' which means unlimited retries."))
+ translate("Retry limit to connect to an uplink."))
e3.default = 3
-e3.datatype = "range(0,30)"
+e3.datatype = "range(1,10)"
e3.rmempty = false
e4 = e:option(Value, "trm_minquality", translate("Signal Quality Threshold"),
translate("Minimum signal quality threshold as percent for conditional uplink (dis-) connections."))
-e4.default = 30
-e4.datatype = "range(0,100)"
+e4.default = 35
+e4.datatype = "range(20,80)"
e4.rmempty = false
e5 = e:option(Value, "trm_maxwait", translate("Interface Timeout"),
- translate("How long should travelmate wait for a successful wlan interface reload."))
+ translate("How long should travelmate wait for a successful wlan uplink connection."))
e5.default = 30
-e5.datatype = "range(5,60)"
+e5.datatype = "range(20,40)"
e5.rmempty = false
e6 = e:option(Value, "trm_timeout", translate("Overall Timeout"),
translate("Timeout in seconds between retries in 'automatic' mode."))
e6.default = 60
-e6.datatype = "range(60,300)"
+e6.datatype = "range(30,300)"
e6.rmempty = false
return m
diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm
new file mode 100644
index 000000000..13342a3e6
--- /dev/null
+++ b/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm
@@ -0,0 +1,62 @@
+<%#
+Copyright 2018 Dirk Brenken (dev@brenken.org)
+This is free software, licensed under the Apache License, Version 2.0
+-%>
+
+<%+header%>
+
+<div class="cbi-map">
+ <div class="cbi-map-descr">
+ <%=translate("Here you'll find the QR codes from all of your configured Access Points. It allows you to connect your Android or iOS devices to your router's WiFi using the QR code shown below.")%>
+ </div>
+<%-
+ local write = io.write
+ local uci = require("luci.model.uci").cursor()
+
+ uci:foreach("wireless", "wifi-iface", function(s)
+ local device = s.device or ""
+ local mode = s.mode or ""
+ local ssid = s.ssid or ""
+ local enc = s.encryption or ""
+ local key = s.key or ""
+ local hidden = s.hidden or "false"
+ local disabled = s.disabled or ""
+ local wep_slots = {s.key1 or "", s.key2 or "", s.key3 or "", s.key4 or ""}
+
+ if device and mode == "ap" and disabled ~= "1" then
+ if string.match(enc, '^psk') then
+ enc = "WPA"
+ elseif string.match(enc, '^wep') then
+ enc = "WEP"
+ if tonumber(key) then
+ key = wep_slots[tonumber(key)]
+ end
+ elseif enc == "none" then
+ enc = "nopass"
+ key = "nokey"
+ else
+ enc = ""
+ end
+ if hidden == "1" then
+ hidden = "true"
+ end
+ if ssid and enc and key then
+ local e_ssid = string.gsub(ssid,"[\"\\';:, ]",[[\\\%1]])
+ local e_key = string.gsub(key,"[\"\\';:, ]",[[\\\%1]])
+ local qrcode = ""
+ if nixio.fs.access("/usr/bin/qrencode") then
+ qrcode = luci.sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- 'WIFI:S:\"'" .. e_ssid .. "'\";T:'" .. enc .. "';P:\"'" .. e_key .. "'\";H:'" .. hidden .. "';'")
+ end
+-%>
+ <fieldset class="cbi-section">
+ <legend>AP on <%=device%> with SSID "<%=ssid%>"</legend>
+ <h3 name="content"><%=qrcode%></h3>
+ </fieldset>
+<%-
+ end
+ end
+ end)
+%>
+</div>
+
+<%+footer%>
diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm
index a26733995..1dacb6e24 100644
--- a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm
+++ b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm
@@ -12,7 +12,6 @@ This is free software, licensed under the Apache License, Version 2.0
<%+header%>
<div class="cbi-map">
-<h2 name="content"><%:Wireless Stations%></h2>
<div class="cbi-map-descr">
<%=translatef("Provides an overview of all configured uplinks for the travelmate interface (%s). You can edit, delete or re-order existing uplinks or scan for a new one. The currently used uplink is emphasized in blue.", trmiface)%>
</div>
diff --git a/applications/luci-app-travelmate/po/ja/travelmate.po b/applications/luci-app-travelmate/po/ja/travelmate.po
index 56e3badab..30f34ef30 100644
--- a/applications/luci-app-travelmate/po/ja/travelmate.po
+++ b/applications/luci-app-travelmate/po/ja/travelmate.po
@@ -7,11 +7,14 @@ msgstr ""
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 2.0.5\n"
+"X-Generator: Poedit 2.0.6\n"
"Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"Language: ja\n"
+msgid "AP QR-Codes"
+msgstr "AP QR-コード"
+
msgid "Actions"
msgstr "操作"
@@ -43,6 +46,16 @@ msgstr "BSSID"
msgid "Back to overview"
msgstr "概要へ戻る"
+msgid "Captive Portal Detection"
+msgstr "キャプティブポータル検知"
+
+msgid ""
+"Check the internet availability, log captive portal redirections and keep "
+"the uplink connection 'alive'."
+msgstr ""
+"インターネットの利用可否を確認し、キャプティブポータル リダイレクトを記録して"
+"アップリンク接続を 'alive' として保持します。"
+
msgid "Cipher"
msgstr "暗号化方式"
@@ -135,13 +148,18 @@ msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
msgstr ""
"'trigger' モード時に、手動でアップリンクの再スキャンと再接続を行います。"
-msgid "How long should travelmate wait for a successful wlan interface reload."
+msgid ""
+"Here you'll find the QR codes from all of your configured Access Points. It "
+"allows you to connect your Android or iOS devices to your router's WiFi "
+"using the QR code shown below."
msgstr ""
-"無線LAN インターフェースのリロードが成功するまでの、Travelmate の待機時間で"
-"す。"
+"ここには、構成済みの全アクセスポイントの QR コードを表示しています。以下の "
+"QR コードを使用して、 Android または iOS デバイスをルータの WiFi に接続するこ"
+"とができます。"
-msgid "How many times should travelmate try to connect to an Uplink."
-msgstr "Travelmate がアップリンクへの接続を試行する回数です。"
+msgid ""
+"How long should travelmate wait for a successful wlan uplink connection."
+msgstr "Travelmate が無線アップリンクへの接続成功を待つ時間です。"
msgid "Identity"
msgstr "ID"
@@ -171,6 +189,13 @@ msgstr "最終実行日時"
msgid "Manual Rescan"
msgstr "手動再スキャン"
+msgid ""
+"Minimum signal quality threshold as percent for conditional uplink (dis-) "
+"connections."
+msgstr ""
+"条件付きアップリンク接続(または切断)のための、シグナル品質閾値の下限(%)で"
+"す。"
+
msgid "Move down"
msgstr "下へ"
@@ -233,6 +258,9 @@ msgstr "再スキャン"
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
msgstr "Travelmate が指定された無線に接続するよう制御します。(例: 'radio0')"
+msgid "Retry limit to connect to an uplink."
+msgstr "アップリンクへの接続を試行する回数です。"
+
msgid "Runtime Information"
msgstr "実行情報"
@@ -248,6 +276,9 @@ msgstr "保存"
msgid "Scan"
msgstr "スキャン:"
+msgid "Signal Quality Threshold"
+msgstr "シグナル品質閾値"
+
msgid "Signal strength"
msgstr "信号強度"
@@ -298,24 +329,20 @@ msgstr ""
msgid "Timeout in seconds between retries in 'automatic' mode."
msgstr "'automatic' モード時に接続を確認または再試行する間隔(秒)です。"
-msgid "To disable this feature set it to '0' which means unlimited retries."
-msgstr ""
-"この機能を無効にして接続の再試行を無制限にする場合、 '0' を設定します。"
-
msgid "Travelmate"
msgstr "Travelmate"
msgid "Travelmate Logfile"
msgstr "Travelmate ログファイル"
-msgid "Travelmate Status"
-msgstr "Travelmate ステータス"
+msgid "Travelmate Status (Quality)"
+msgstr "Travelmate ステータス(品質)"
msgid "Travelmate Version"
msgstr "Travelmate バージョン"
-msgid "Trigger delay"
-msgstr "トリガー遅延"
+msgid "Trigger Delay"
+msgstr "トリガ遅延"
msgid "Unknown"
msgstr "不明"
@@ -365,20 +392,8 @@ msgstr ""
"ファイアウォールの wan ゾーンに追加します。このステップは、一度だけ実行される"
"必要があります。"
-msgid "connected"
-msgstr "接続済"
-
-msgid "error"
-msgstr "エラー"
-
msgid "hidden"
msgstr "(不明)"
msgid "n/a"
msgstr "利用不可"
-
-msgid "not connected"
-msgstr "未接続"
-
-msgid "running"
-msgstr "実行中"
diff --git a/applications/luci-app-travelmate/po/pt-br/travelmate.po b/applications/luci-app-travelmate/po/pt-br/travelmate.po
index cf17b024e..7cb6ac061 100644
--- a/applications/luci-app-travelmate/po/pt-br/travelmate.po
+++ b/applications/luci-app-travelmate/po/pt-br/travelmate.po
@@ -12,6 +12,9 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Language: pt_BR\n"
+msgid "AP QR-Codes"
+msgstr ""
+
msgid "Actions"
msgstr ""
@@ -43,6 +46,14 @@ msgstr ""
msgid "Back to overview"
msgstr ""
+msgid "Captive Portal Detection"
+msgstr ""
+
+msgid ""
+"Check the internet availability, log captive portal redirections and keep "
+"the uplink connection 'alive'."
+msgstr ""
+
msgid "Cipher"
msgstr ""
@@ -129,10 +140,14 @@ msgstr ""
msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
msgstr ""
-msgid "How long should travelmate wait for a successful wlan interface reload."
+msgid ""
+"Here you'll find the QR codes from all of your configured Access Points. It "
+"allows you to connect your Android or iOS devices to your router's WiFi "
+"using the QR code shown below."
msgstr ""
-msgid "How many times should travelmate try to connect to an Uplink."
+msgid ""
+"How long should travelmate wait for a successful wlan uplink connection."
msgstr ""
msgid "Identity"
@@ -161,6 +176,11 @@ msgstr ""
msgid "Manual Rescan"
msgstr ""
+msgid ""
+"Minimum signal quality threshold as percent for conditional uplink (dis-) "
+"connections."
+msgstr ""
+
msgid "Move down"
msgstr ""
@@ -219,6 +239,9 @@ msgstr ""
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
msgstr ""
+msgid "Retry limit to connect to an uplink."
+msgstr ""
+
msgid "Runtime Information"
msgstr ""
@@ -234,6 +257,9 @@ msgstr ""
msgid "Scan"
msgstr ""
+msgid "Signal Quality Threshold"
+msgstr ""
+
msgid "Signal strength"
msgstr ""
@@ -274,22 +300,19 @@ msgstr ""
msgid "Timeout in seconds between retries in 'automatic' mode."
msgstr ""
-msgid "To disable this feature set it to '0' which means unlimited retries."
-msgstr ""
-
msgid "Travelmate"
msgstr "Travelmate"
msgid "Travelmate Logfile"
msgstr ""
-msgid "Travelmate Status"
+msgid "Travelmate Status (Quality)"
msgstr ""
msgid "Travelmate Version"
msgstr ""
-msgid "Trigger delay"
+msgid "Trigger Delay"
msgstr ""
msgid "Unknown"
@@ -338,24 +361,12 @@ msgid ""
"add it to the wan zone of the firewall. This step has only to be done once."
msgstr ""
-msgid "connected"
-msgstr ""
-
-msgid "error"
-msgstr ""
-
msgid "hidden"
msgstr ""
msgid "n/a"
msgstr ""
-msgid "not connected"
-msgstr ""
-
-msgid "running"
-msgstr ""
-
#~ msgid ""
#~ "Brief advice: Create a wwan interface, configure it to use dhcp and add "
#~ "it to the wan zone in firewall. Create the wifi interfaces to be used "
diff --git a/applications/luci-app-travelmate/po/ru/travelmate.po b/applications/luci-app-travelmate/po/ru/travelmate.po
index fe0e47647..0b04e2783 100644
--- a/applications/luci-app-travelmate/po/ru/travelmate.po
+++ b/applications/luci-app-travelmate/po/ru/travelmate.po
@@ -15,6 +15,9 @@ msgstr ""
"Project-Info: Это технический перевод, не дословный. Главное-удобный русский "
"интерфейс, все проверялось в графическом режиме, совместим с другими apps\n"
+msgid "AP QR-Codes"
+msgstr ""
+
msgid "Actions"
msgstr "Действия"
@@ -46,6 +49,14 @@ msgstr "BSSID"
msgid "Back to overview"
msgstr "Назад в меню"
+msgid "Captive Portal Detection"
+msgstr ""
+
+msgid ""
+"Check the internet availability, log captive portal redirections and keep "
+"the uplink connection 'alive'."
+msgstr ""
+
msgid "Cipher"
msgstr "Алгоритм шифрования"
@@ -138,13 +149,15 @@ msgstr ""
"Принудительно выполнить повторное сканирование/повторное подключение внешних "
"сетей в режиме 'ручной'."
-msgid "How long should travelmate wait for a successful wlan interface reload."
+msgid ""
+"Here you'll find the QR codes from all of your configured Access Points. It "
+"allows you to connect your Android or iOS devices to your router's WiFi "
+"using the QR code shown below."
msgstr ""
-"Временная задержка необходима TravelMate для полной перезагрузки wlan "
-"интерфейса."
-msgid "How many times should travelmate try to connect to an Uplink."
-msgstr "Сколько раз TravelMate должен пытаться подключиться к сети. "
+msgid ""
+"How long should travelmate wait for a successful wlan uplink connection."
+msgstr ""
msgid "Identity"
msgstr "Идентификация EAP"
@@ -174,6 +187,11 @@ msgstr "Дата последнего запуска"
msgid "Manual Rescan"
msgstr "Поиск сети вручную"
+msgid ""
+"Minimum signal quality threshold as percent for conditional uplink (dis-) "
+"connections."
+msgstr ""
+
msgid "Move down"
msgstr "Переместить вниз"
@@ -238,6 +256,9 @@ msgstr "Пересканировать"
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
msgstr "Выделить TravelMate-у конкретное Wi-Fi устройство, например 'radio0'."
+msgid "Retry limit to connect to an uplink."
+msgstr ""
+
msgid "Runtime Information"
msgstr "Информация о состоянии"
@@ -253,6 +274,9 @@ msgstr "Сохранить"
msgid "Scan"
msgstr "Поиск"
+msgid "Signal Quality Threshold"
+msgstr ""
+
msgid "Signal strength"
msgstr "Мощность сигнала"
@@ -305,25 +329,20 @@ msgstr ""
"Время ожидания в секундах между повторными попытками соединения в режиме "
"'автоматически'."
-msgid "To disable this feature set it to '0' which means unlimited retries."
-msgstr ""
-"<br />Чтобы отключить эту функцию, установите значение '0', что означает "
-"неограниченное количество попыток."
-
msgid "Travelmate"
msgstr "TravelMate"
msgid "Travelmate Logfile"
msgstr "Системный журнал TravelMate"
-msgid "Travelmate Status"
-msgstr "Состояние Travelmate"
+msgid "Travelmate Status (Quality)"
+msgstr ""
msgid "Travelmate Version"
msgstr "Версия TravelMate"
-msgid "Trigger delay"
-msgstr "Задержка запуска"
+msgid "Trigger Delay"
+msgstr ""
msgid "Unknown"
msgstr "Неизвестно"
@@ -371,20 +390,40 @@ msgid ""
"add it to the wan zone of the firewall. This step has only to be done once."
msgstr "добавить в wan зону межсетевого экрана. Можно сделать только один раз."
-msgid "connected"
-msgstr "подключен"
-
-msgid "error"
-msgstr "ошибка"
-
msgid "hidden"
msgstr "скрытый"
msgid "n/a"
msgstr "нет данных"
-msgid "not connected"
-msgstr "не подключено"
+#~ msgid ""
+#~ "How long should travelmate wait for a successful wlan interface reload."
+#~ msgstr ""
+#~ "Временная задержка необходима TravelMate для полной перезагрузки wlan "
+#~ "интерфейса."
+
+#~ msgid "How many times should travelmate try to connect to an Uplink."
+#~ msgstr "Сколько раз TravelMate должен пытаться подключиться к сети. "
+
+#~ msgid "To disable this feature set it to '0' which means unlimited retries."
+#~ msgstr ""
+#~ "<br />Чтобы отключить эту функцию, установите значение '0', что означает "
+#~ "неограниченное количество попыток."
+
+#~ msgid "Travelmate Status"
+#~ msgstr "Состояние Travelmate"
+
+#~ msgid "Trigger delay"
+#~ msgstr "Задержка запуска"
+
+#~ msgid "connected"
+#~ msgstr "подключен"
+
+#~ msgid "error"
+#~ msgstr "ошибка"
+
+#~ msgid "not connected"
+#~ msgstr "не подключено"
-msgid "running"
-msgstr "работает"
+#~ msgid "running"
+#~ msgstr "работает"
diff --git a/applications/luci-app-travelmate/po/templates/travelmate.pot b/applications/luci-app-travelmate/po/templates/travelmate.pot
index aeefa491d..e27c61a9d 100644
--- a/applications/luci-app-travelmate/po/templates/travelmate.pot
+++ b/applications/luci-app-travelmate/po/templates/travelmate.pot
@@ -1,6 +1,9 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
+msgid "AP QR-Codes"
+msgstr ""
+
msgid "Actions"
msgstr ""
@@ -32,6 +35,14 @@ msgstr ""
msgid "Back to overview"
msgstr ""
+msgid "Captive Portal Detection"
+msgstr ""
+
+msgid ""
+"Check the internet availability, log captive portal redirections and keep "
+"the uplink connection 'alive'."
+msgstr ""
+
msgid "Cipher"
msgstr ""
@@ -118,10 +129,14 @@ msgstr ""
msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
msgstr ""
-msgid "How long should travelmate wait for a successful wlan interface reload."
+msgid ""
+"Here you'll find the QR codes from all of your configured Access Points. It "
+"allows you to connect your Android or iOS devices to your router's WiFi "
+"using the QR code shown below."
msgstr ""
-msgid "How many times should travelmate try to connect to an Uplink."
+msgid ""
+"How long should travelmate wait for a successful wlan uplink connection."
msgstr ""
msgid "Identity"
@@ -150,6 +165,11 @@ msgstr ""
msgid "Manual Rescan"
msgstr ""
+msgid ""
+"Minimum signal quality threshold as percent for conditional uplink (dis-) "
+"connections."
+msgstr ""
+
msgid "Move down"
msgstr ""
@@ -208,6 +228,9 @@ msgstr ""
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
msgstr ""
+msgid "Retry limit to connect to an uplink."
+msgstr ""
+
msgid "Runtime Information"
msgstr ""
@@ -223,6 +246,9 @@ msgstr ""
msgid "Scan"
msgstr ""
+msgid "Signal Quality Threshold"
+msgstr ""
+
msgid "Signal strength"
msgstr ""
@@ -263,22 +289,19 @@ msgstr ""
msgid "Timeout in seconds between retries in 'automatic' mode."
msgstr ""
-msgid "To disable this feature set it to '0' which means unlimited retries."
-msgstr ""
-
msgid "Travelmate"
msgstr ""
msgid "Travelmate Logfile"
msgstr ""
-msgid "Travelmate Status"
+msgid "Travelmate Status (Quality)"
msgstr ""
msgid "Travelmate Version"
msgstr ""
-msgid "Trigger delay"
+msgid "Trigger Delay"
msgstr ""
msgid "Unknown"
@@ -327,20 +350,8 @@ msgid ""
"add it to the wan zone of the firewall. This step has only to be done once."
msgstr ""
-msgid "connected"
-msgstr ""
-
-msgid "error"
-msgstr ""
-
msgid "hidden"
msgstr ""
msgid "n/a"
msgstr ""
-
-msgid "not connected"
-msgstr ""
-
-msgid "running"
-msgstr ""
diff --git a/applications/luci-app-wol/luasrc/model/cbi/wol.lua b/applications/luci-app-wol/luasrc/model/cbi/wol.lua
index ec6a1be2a..d40dde017 100644
--- a/applications/luci-app-wol/luasrc/model/cbi/wol.lua
+++ b/applications/luci-app-wol/luasrc/model/cbi/wol.lua
@@ -2,6 +2,7 @@
-- Licensed to the public under the Apache License 2.0.
local sys = require "luci.sys"
+local ipc = require "luci.ip"
local fs = require "nixio.fs"
m = SimpleForm("wol", translate("Wake on LAN"),
@@ -58,7 +59,8 @@ end
function host.write(self, s, val)
local host = luci.http.formvalue("cbid.wol.1.mac")
- if host and #host > 0 and host:match("^[a-fA-F0-9:]+$") then
+ local mac = ipc.checkmac(host)
+ if mac then
local cmd
local util = luci.http.formvalue("cbid.wol.1.binary") or (
has_ewk and "/usr/bin/etherwake" or "/usr/bin/wol"
@@ -69,10 +71,10 @@ function host.write(self, s, val)
local broadcast = luci.http.formvalue("cbid.wol.1.broadcast")
cmd = "%s -D%s %s %q" %{
util, (iface ~= "" and " -i %q" % iface or ""),
- (broadcast == "1" and " -b" or ""), host
+ (broadcast == "1" and " -b" or ""), mac
}
else
- cmd = "%s -v %q" %{ util, host }
+ cmd = "%s -v %q" %{ util, mac }
end
local msg = "<p><strong>%s</strong><br /><br /><code>%s<br /><br />" %{
diff --git a/contrib/package/community-profiles/files/etc/config/profile_potsdam b/contrib/package/community-profiles/files/etc/config/profile_potsdam
index 9bdb60323..6a8f1f14b 100644
--- a/contrib/package/community-profiles/files/etc/config/profile_potsdam
+++ b/contrib/package/community-profiles/files/etc/config/profile_potsdam
@@ -1,7 +1,7 @@
config 'community' 'profile'
option 'name' 'Freifunk Potsdam'
option 'homepage' 'http://potsdam.freifunk.net'
- option 'ssid' 'Freifunk-Potsdam-XXX-YYY'
+ option 'ssid' 'freifunk-potsdam.de'
option 'mesh_network' '10.22.0.0/16'
option 'splash_network' '192.168.22.0/24'
option 'splash_prefix' '24'
diff --git a/documentation/api/modules/luci.http.protocol.html b/documentation/api/modules/luci.http.protocol.html
index 57063bbcf..e6e93ad3d 100644
--- a/documentation/api/modules/luci.http.protocol.html
+++ b/documentation/api/modules/luci.http.protocol.html
@@ -341,7 +341,7 @@ Ltn12 source function
Decode a mime encoded http message body with multipart/form-data
Content-Type. Stores all extracted data associated with its parameter name
-in the params table within the given message object. Multiple parameter
+in the params table within the given message object. Multiple parameter
values are stored as tables, ordinary ones as strings.
If an optional file callback function is given then it is feeded with the
file contents chunk by chunk and only the extracted file name is stored
@@ -556,7 +556,7 @@ The decoded string
Decode an urlencoded http message body with application/x-www-urlencoded
Content-Type. Stores all extracted data associated with its parameter name
-in the params table within the given message object. Multiple parameter
+in the params table within the given message object. Multiple parameter
values are stored as tables, ordinary ones as strings.
diff --git a/documentation/api/modules/luci.ip.cidr.html b/documentation/api/modules/luci.ip.cidr.html
index ce8c56795..5a2b06ec6 100644
--- a/documentation/api/modules/luci.ip.cidr.html
+++ b/documentation/api/modules/luci.ip.cidr.html
@@ -260,6 +260,30 @@ Checks whether the CIDR instance is an IPv6 mapped IPv4 address
</tr>
<tr>
+ <td class="name" nowrap><a href="#cidr.ismac">cidr:ismac</a>&nbsp;()</td>
+ <td class="summary">
+
+Checks whether the CIDR instance is an ethernet MAC address range
+ </td>
+ </tr>
+
+ <tr>
+ <td class="name" nowrap><a href="#cidr.ismaclocal">cidr:ismaclocal</a>&nbsp;()</td>
+ <td class="summary">
+
+Checks whether the CIDR instance is a locally administered (LAA) MAC address
+ </td>
+ </tr>
+
+ <tr>
+ <td class="name" nowrap><a href="#cidr.ismacmcast">cidr:ismacmcast</a>&nbsp;()</td>
+ <td class="summary">
+
+Checks whether the CIDR instance is a multicast MAC address
+ </td>
+ </tr>
+
+ <tr>
<td class="name" nowrap><a href="#cidr.lower">cidr:lower</a>&nbsp;(addr)</td>
<td class="summary">
@@ -323,6 +347,20 @@ Derive mapped IPv4 address of CIDR instance.</td>
</tr>
<tr>
+ <td class="name" nowrap><a href="#cidr.tomac">cidr:tomac</a>&nbsp;()</td>
+ <td class="summary">
+
+Derive MAC address of IPv6 link local CIDR instance.</td>
+ </tr>
+
+ <tr>
+ <td class="name" nowrap><a href="#cidr.tolinklocal">cidr:tolinklocal</a>&nbsp;()</td>
+ <td class="summary">
+
+Derive IPv6 link local address from MAC address CIDR instance.</td>
+ </tr>
+
+ <tr>
<td class="name" nowrap><a href="#cidr.contains">cidr:contains</a>&nbsp;(addr)</td>
<td class="summary">
@@ -405,6 +443,10 @@ Checks whether the CIDR instance is an IPv4 address range
cidr:is6
</a>
+ <li><a href="#cidr.ismac">
+ cidr:ismac
+ </a>
+
</ul>
</dd>
@@ -499,6 +541,10 @@ Checks whether the CIDR instance is an IPv6 address range
cidr:is4
</a>
+ <li><a href="#cidr.ismac">
+ cidr:ismac
+ </a>
+
</ul>
</dd>
@@ -566,13 +612,108 @@ end</pre>
+<dt><a name="cidr.ismac"></a><strong>cidr:ismac</strong>&nbsp;()</dt>
+<dd>
+
+
+Checks whether the CIDR instance is an ethernet MAC address range
+
+
+
+
+
+
+
+
+<h3>Return value:</h3>
+<code>true</code> if the CIDR is a MAC address range, else <code>false</code>
+
+
+
+<h3>See also:</h3>
+<ul>
+
+ <li><a href="#cidr.is4">
+ cidr:is4
+ </a>
+
+ <li><a href="#cidr.is6">
+ cidr:is6
+ </a>
+
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="cidr.ismaclocal"></a><strong>cidr:ismaclocal</strong>&nbsp;()</dt>
+<dd>
+
+
+Checks whether the CIDR instance is a locally administered (LAA) MAC address
+
+
+
+
+
+
+<h3>Usage:</h3>
+<pre>local mac = luci.ip.new("02:C0:FF:EE:00:01")
+if mac:ismaclocal() then
+ print("Is an LAA MAC address")
+end</pre>
+
+
+
+<h3>Return value:</h3>
+<code>true</code> if the MAC address sets the locally administered bit.
+
+
+
+</dd>
+
+
+
+
+<dt><a name="cidr.ismacmcast"></a><strong>cidr:ismacmcast</strong>&nbsp;()</dt>
+<dd>
+
+
+Checks whether the CIDR instance is a multicast MAC address
+
+
+
+
+
+
+<h3>Usage:</h3>
+<pre>local mac = luci.ip.new("01:00:5E:7F:00:10")
+if addr:ismacmcast() then
+ print("Is a multicast MAC address")
+end</pre>
+
+
+
+<h3>Return value:</h3>
+<code>true</code> if the MAC address sets the multicast bit.
+
+
+
+</dd>
+
+
+
+
<dt><a name="cidr.lower"></a><strong>cidr:lower</strong>&nbsp;(addr)</dt>
<dd>
Checks whether this CIDR instance is lower than the given argument.
The comparisation follows these rules:
-<ul><li>An IPv4 address is always lower than an IPv6 address</li>
+<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses
+are considered lower than MAC addresses</li>
<li>Prefix sizes are ignored</li></ul>
@@ -595,7 +736,8 @@ The comparisation follows these rules:
print(addr:lower(addr)) -- false
print(addr:lower("10.10.10.10/24")) -- false
print(addr:lower(luci.ip.new("::1"))) -- true
-print(addr:lower(luci.ip.new("192.168.200.1"))) -- true</pre>
+print(addr:lower(luci.ip.new("192.168.200.1"))) -- true
+print(addr:lower(luci.ip.new("00:14:22:01:23:45"))) -- true</pre>
@@ -629,7 +771,8 @@ print(addr:lower(luci.ip.new("192.168.200.1"))) -- true</pre>
Checks whether this CIDR instance is higher than the given argument.
The comparisation follows these rules:
-<ul><li>An IPv4 address is always lower than an IPv6 address</li>
+<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses
+are considered lower than MAC addresses</li>
<li>Prefix sizes are ignored</li></ul>
@@ -652,7 +795,8 @@ The comparisation follows these rules:
print(addr:higher(addr)) -- false
print(addr:higher("10.10.10.10/24")) -- true
print(addr:higher(luci.ip.new("::1"))) -- false
-print(addr:higher(luci.ip.new("192.168.200.1"))) -- false</pre>
+print(addr:higher(luci.ip.new("192.168.200.1"))) -- false
+print(addr:higher(luci.ip.new("00:14:22:01:23:45"))) -- false</pre>
@@ -709,7 +853,11 @@ print(addr:equal(luci.ip.new("::1"))) -- false
local addr6 = luci.ip.new("::1")
print(addr6:equal("0:0:0:0:0:0:0:1/64")) -- true
-print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false</pre>
+print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false
+
+local mac = luci.ip.new("00:14:22:01:23:45")
+print(mac:equal("0:14:22:1:23:45")) -- true
+print(mac:equal(luci.ip.new("01:23:45:67:89:AB")) -- false</pre>
@@ -752,8 +900,8 @@ else the current prefix size is returned.
<li>
mask: Either a number containing the number of bits (<code>0..32</code>
- for IPv4, <code>0..128</code> for IPv6) or a string containing a valid
- netmask (optional)
+ for IPv4, <code>0..128</code> for IPv6 or <code>0..48</code> for MAC addresses) or a string
+ containing a valid netmask (optional)
</li>
</ul>
@@ -800,8 +948,8 @@ optional mask parameter.
<li>
mask: Either a number containing the number of bits (<code>0..32</code>
- for IPv4, <code>0..128</code> for IPv6) or a string containing a valid
- netmask (optional)
+ for IPv4, <code>0..128</code> for IPv6 or <code>0..48</code> for MAC addresses) or a string
+ containing a valid netmask (optional)
</li>
</ul>
@@ -837,7 +985,7 @@ CIDR instance representing the network address
Derive host address of CIDR instance.
This function essentially constructs a copy of this CIDR with the prefix size
-set to <code>32</code> for IPv4 and <code>128</code> for IPv6.
+set to <code>32</code> for IPv4, <code>128</code> for IPv6 or <code>48</code> for MAC addresses.
@@ -877,8 +1025,8 @@ prefix size can be overridden by the optional mask parameter.
<li>
mask: Either a number containing the number of bits (<code>0..32</code>
- for IPv4, <code>0..128</code> for IPv6) or a string containing a valid
- netmask (optional)
+ for IPv4, <code>0..128</code> for IPv6 or <code>0..48</code> for MAC addresses) or a string
+ containing a valid netmask (optional)
</li>
</ul>
@@ -913,8 +1061,8 @@ Derive broadcast address of CIDR instance.
Constructs a CIDR instance representing the broadcast address of this instance.
The used prefix size can be overridden by the optional mask parameter.
-This function has no effect on IPv6 instances, it will return nothing in this
-case.
+This function has no effect on IPv6 or MAC address instances, it will return
+nothing in this case.
@@ -922,9 +1070,8 @@ case.
<ul>
<li>
- mask: Either a number containing the number of bits (<code>0..32</code>
- for IPv4, <code>0..128</code> for IPv6) or a string containing a valid
- netmask (optional)
+ mask: Either a number containing the number of bits (<code>0..32</code> for IPv4) or
+ a string containing a valid netmask (optional)
</li>
</ul>
@@ -960,8 +1107,8 @@ Derive mapped IPv4 address of CIDR instance.
Constructs a CIDR instance representing the IPv4 address of the IPv6 mapped
IPv4 address in this instance.
-This function has no effect on IPv4 instances or IPv6 instances which are not a
-mapped address, it will return nothing in this case.
+This function has no effect on IPv4 instances, MAC address instances or IPv6
+instances which are not a mapped address, it will return nothing in this case.
@@ -985,6 +1132,74 @@ Return a new CIDR instance representing the IPv4 address if this
+<dt><a name="cidr.tomac"></a><strong>cidr:tomac</strong>&nbsp;()</dt>
+<dd>
+
+
+Derive MAC address of IPv6 link local CIDR instance.
+
+Constructs a CIDR instance representing the MAC address contained in the IPv6
+link local address of this instance.
+
+This function has no effect on IPv4 instances, MAC address instances or IPv6
+instances which are not a link local address, it will return nothing in this
+case.
+
+
+
+
+
+
+<h3>Usage:</h3>
+<pre>local addr = luci.ip.new("fe80::6666:b3ff:fe47:e1b9")
+print(addr:tomac()) -- "64:66:B3:47:E1:B9"</pre>
+
+
+
+<h3>Return value:</h3>
+Return a new CIDR instance representing the MAC address if this
+ instance is an IPv6 link local address, else return nothing.
+
+
+
+</dd>
+
+
+
+
+<dt><a name="cidr.tolinklocal"></a><strong>cidr:tolinklocal</strong>&nbsp;()</dt>
+<dd>
+
+
+Derive IPv6 link local address from MAC address CIDR instance.
+
+Constructs a CIDR instance representing the IPv6 link local address of the
+MAC address represented by this instance.
+
+This function has no effect on IPv4 instances or IPv6 instances, it will return
+nothing in this case.
+
+
+
+
+
+
+<h3>Usage:</h3>
+<pre>local mac = luci.ip.new("64:66:B3:47:E1:B9")
+print(mac:tolinklocal()) -- "fe80::6666:b3ff:fe47:e1b9"</pre>
+
+
+
+<h3>Return value:</h3>
+Return a new CIDR instance representing the IPv6 link local address.
+
+
+
+</dd>
+
+
+
+
<dt><a name="cidr.contains"></a><strong>cidr:contains</strong>&nbsp;(addr)</dt>
<dd>
@@ -1014,7 +1229,11 @@ print(range:contains("10.0.0.0/8")) -- false
local range6 = luci.ip.new("fe80::/10")
print(range6:contains("fe80::221:63f:fe75:aa17/64")) -- true
-print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false</pre>
+print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false
+
+local intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24")
+print(intel_macs:contains("C0:B6:F9:A3:C:11")) -- true
+print(intel_macs:contains("64:66:B3:47:E1:B9")) -- false</pre>
@@ -1059,30 +1278,40 @@ address space, the result is set to the highest possible address.
<h3>Usage:</h3>
<pre>local addr = luci.ip.new("192.168.1.1/24")
-print(addr:add(250)) -- "192.168.1.251/24"
-print(addr:add("0.0.99.0")) -- "192.168.100.1/24"
+print(addr:add(250)) -- "192.168.1.251/24"
+print(addr:add("0.0.99.0")) -- "192.168.100.1/24"
-addr:add(256, true) -- true
-print(addr) -- "192.168.2.1/24
+addr:add(256, true) -- true
+print(addr) -- "192.168.2.1/24
-addr:add("255.0.0.0", true) -- false (overflow)
-print(addr) -- "255.255.255.255/24
+addr:add("255.0.0.0", true) -- false (overflow)
+print(addr) -- "255.255.255.255/24
local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64")
-print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64"
-print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64"
+print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64"
+print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64"
+
+addr6:add(256, true) -- true
+print(addr6) -- "fe80::221:63f:fe75:ab17/64
+
+addr6:add("ffff::", true) -- false (overflow)
+print(addr6) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"
+
+local mac = luci.ip.new("00:14:22:01:23:45")
+print(mac:add(256)) -- "00:14:22:01:24:45"
+print(mac:add("0:0:0:0:FF:0") -- "00:14:22:02:22:45"
-addr:add(256, true) -- true
-print(addr) -- "fe80::221:63f:fe75:ab17/64
+mac:add(256, true) -- true
+print(mac) -- "00:14:22:01:24:45"
-addr:add("ffff::", true) -- false (overflow)
-print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"</pre>
+mac:add("FF:FF:0:0:0:0", true) -- false (overflow)
+print(mac) -- "FF:FF:FF:FF:FF:FF"</pre>
<h3>Return value:</h3>
<ul>
- <li>When adding inplace: Return <code>true</code> if the addition succeeded
+ <li>When adding inplace: Return <code>true</code> if the addition succeded
or <code>false</code> when the addition overflowed.</li>
<li>When deriving new CIDR: Return new instance representing the value of
this instance plus the added amount or the highest possible address if
@@ -1099,7 +1328,7 @@ print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"</pr
<dd>
-Subtract given amount from CIDR instance. If the result would under, the lowest
+Subtract given amount from CIDR instance. If the result would under, the lowest
possible address is returned.
@@ -1142,16 +1371,26 @@ addr:sub(256, true) -- true
print(addr) -- "fe80::221:63f:fe75:a917/64"
addr:sub("ffff::", true) -- false (underflow)
-print(addr) -- "::/64"</pre>
+print(addr) -- "::/64"
+
+local mac = luci.ip.new("00:14:22:01:23:45")
+print(mac:sub(256)) -- "00:14:22:01:22:45"
+print(mac:sub("0:0:0:0:FF:0") -- "00:14:22:00:24:45"
+
+mac:sub(256, true) -- true
+print(mac) -- "00:14:22:01:22:45"
+
+mac:sub("FF:FF:0:0:0:0", true) -- false (overflow)
+print(mac) -- "00:00:00:00:00:00"</pre>
<h3>Return value:</h3>
<ul>
- <li>When subtracting inplace: Return <code>true</code> if the subtraction
- succeeded or <code>false</code> when the subtraction underflowed.</li>
+ <li>When subtracting inplace: Return <code>true</code> if the subtraction
+ succeeded or <code>false</code> when the subtraction underflowed.</li>
<li>When deriving new CIDR: Return new instance representing the value of
- this instance minus the subtracted amount or the lowest address if
+ this instance minus the subtracted amount or the lowest address if
the subtraction underflowed.</li></ul>
@@ -1177,7 +1416,10 @@ Calculate the lowest possible host address within this CIDR instance.
print(addr:minhost()) -- "192.168.123.1"
local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
-print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"</pre>
+print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"
+
+local mac = luci.ip.new("00:14:22:01:22:45/32")
+print(mac:minhost()) -- "00:14:22:01:00:01"</pre>
@@ -1208,7 +1450,10 @@ Calculate the highest possible host address within this CIDR instance.
print(addr:maxhost()) -- "192.168.123.254" (.255 is broadcast)
local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
-print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"</pre>
+print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"
+
+local mac = luci.ip.new("00:14:22:01:22:45/32")
+print(mac:maxhost()) -- "00:14:22:01:FF:FF"</pre>
@@ -1229,8 +1474,9 @@ Returns a new CIDR instance representing the highest host address
Convert CIDR instance into string representation.
-If the prefix size of instance is less than 32 for IPv4 or 128 for IPv6, the
-address is returned in the form "address/prefix" otherwise just "address".
+If the prefix size of instance is less than 32 for IPv4, 128 for IPv6 or 48 for
+MACs, the address is returned in the form "address/prefix" otherwise just
+"address".
It is usually not required to call this function directly as CIDR objects
define it as __tostring function in the associated metatable.
diff --git a/documentation/api/modules/luci.ip.html b/documentation/api/modules/luci.ip.html
index 549a55307..1f89626fa 100644
--- a/documentation/api/modules/luci.ip.html
+++ b/documentation/api/modules/luci.ip.html
@@ -232,6 +232,34 @@ Construct a new IPv6 luci.ip.cidr instance.</td>
</tr>
<tr>
+ <td class="name" nowrap><a href="#MAC">MAC</a>&nbsp;(address, netmask)</td>
+ <td class="summary">
+
+Construct a new MAC luci.ip.cidr instance.</td>
+ </tr>
+
+ <tr>
+ <td class="name" nowrap><a href="#checkip4">checkip4</a>&nbsp;(address)</td>
+ <td class="summary">
+
+Verify an IPv4 address.</td>
+ </tr>
+
+ <tr>
+ <td class="name" nowrap><a href="#checkip6">checkip6</a>&nbsp;(address)</td>
+ <td class="summary">
+
+Verify an IPv6 address.</td>
+ </tr>
+
+ <tr>
+ <td class="name" nowrap><a href="#checkmac">checkmac</a>&nbsp;(address)</td>
+ <td class="summary">
+
+Verify an ethernet MAC address.</td>
+ </tr>
+
+ <tr>
<td class="name" nowrap><a href="#route">route</a>&nbsp;(address)</td>
<td class="summary">
@@ -334,6 +362,10 @@ address/mask range.
IPv6
</a>
+ <li><a href="#MAC">
+ MAC
+ </a>
+
</ul>
</dd>
@@ -389,6 +421,10 @@ A <code>luci.ip.cidr</code> object representing the given IPv4 range.
IPv6
</a>
+ <li><a href="#MAC">
+ MAC
+ </a>
+
</ul>
</dd>
@@ -444,6 +480,252 @@ A <code>luci.ip.cidr</code> object representing the given IPv6 range.
IPv4
</a>
+ <li><a href="#MAC">
+ MAC
+ </a>
+
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="MAC"></a><strong>MAC</strong>&nbsp;(address, netmask)</dt>
+<dd>
+
+
+Construct a new MAC luci.ip.cidr instance.
+Throws an error if the given string does not represent a valid ethernet MAC
+address or if the given optional mask is of a different family.
+
+
+<h3>Parameters</h3>
+<ul>
+
+ <li>
+ address: String containing a valid ethernet MAC address, optionally with
+prefix size (CIDR notation) or mask separated by slash.
+ </li>
+
+ <li>
+ netmask: String containing a valid MAC address mask or number
+containing a prefix size between <code>0</code> and <code>48</code> bit.
+Overrides mask embedded in the first argument if specified. (optional)
+ </li>
+
+</ul>
+
+
+
+
+<h3>Usage:</h3>
+<pre>intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24")
+intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/FF:FF:FF:0:0:0")
+intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00", "FF:FF:FF:0:0:0")
+intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24", 48) -- override mask</pre>
+
+
+
+<h3>Return value:</h3>
+A <code>luci.ip.cidr</code> object representing the given MAC address range.
+
+
+
+<h3>See also:</h3>
+<ul>
+
+ <li><a href="#IPv4">
+ IPv4
+ </a>
+
+ <li><a href="#IPv6">
+ IPv6
+ </a>
+
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="checkip4"></a><strong>checkip4</strong>&nbsp;(address)</dt>
+<dd>
+
+
+Verify an IPv4 address.
+
+Checks whether given argument is a preexisting luci.ip.cidr IPv4 address
+instance or a string literal convertible to an IPv4 address and returns a
+plain Lua string containing the canonical representation of the address.
+
+If the argument is not a valid address, returns nothing. This function is
+intended to aid in safely verifying address literals without having to deal
+with exceptions.
+
+
+<h3>Parameters</h3>
+<ul>
+
+ <li>
+ address: String containing a valid IPv4 address or existing
+luci.ip.cidr IPv4 instance.
+ </li>
+
+</ul>
+
+
+
+
+<h3>Usage:</h3>
+<pre>ipv4 = luci.ip.checkip4(luci.ip.new("127.0.0.1")) -- "127.0.0.1"
+ipv4 = luci.ip.checkip4("127.0.0.1") -- "127.0.0.1"
+ipv4 = luci.ip.checkip4("nonesense") -- nothing
+ipv4 = luci.ip.checkip4(123) -- nothing
+ipv4 = luci.ip.checkip4(nil) -- nothing
+ipv4 = luci.ip.checkip4() -- nothing</pre>
+
+
+
+<h3>Return value:</h3>
+A string representing the given IPv4 address.
+
+
+
+<h3>See also:</h3>
+<ul>
+
+ <li><a href="#checkip6">
+ checkip6
+ </a>
+
+ <li><a href="#checkmac">
+ checkmac
+ </a>
+
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="checkip6"></a><strong>checkip6</strong>&nbsp;(address)</dt>
+<dd>
+
+
+Verify an IPv6 address.
+
+Checks whether given argument is a preexisting luci.ip.cidr IPv6 address
+instance or a string literal convertible to an IPv6 address and returns a
+plain Lua string containing the canonical representation of the address.
+
+If the argument is not a valid address, returns nothing. This function is
+intended to aid in safely verifying address literals without having to deal
+with exceptions.
+
+
+<h3>Parameters</h3>
+<ul>
+
+ <li>
+ address: String containing a valid IPv6 address or existing
+luci.ip.cidr IPv6 instance.
+ </li>
+
+</ul>
+
+
+
+
+<h3>Usage:</h3>
+<pre>ipv6 = luci.ip.checkip6(luci.ip.new("0:0:0:0:0:0:0:1")) -- "::1"
+ipv6 = luci.ip.checkip6("0:0:0:0:0:0:0:1") -- "::1"
+ipv6 = luci.ip.checkip6("nonesense") -- nothing
+ipv6 = luci.ip.checkip6(123) -- nothing
+ipv6 = luci.ip.checkip6(nil) -- nothing
+ipv6 = luci.ip.checkip6() -- nothing</pre>
+
+
+
+<h3>Return value:</h3>
+A string representing the given IPv6 address.
+
+
+
+<h3>See also:</h3>
+<ul>
+
+ <li><a href="#checkip4">
+ checkip4
+ </a>
+
+ <li><a href="#checkmac">
+ checkmac
+ </a>
+
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="checkmac"></a><strong>checkmac</strong>&nbsp;(address)</dt>
+<dd>
+
+
+Verify an ethernet MAC address.
+
+Checks whether given argument is a preexisting luci.ip.cidr MAC address
+instance or a string literal convertible to an ethernet MAC and returns a
+plain Lua string containing the canonical representation of the address.
+
+If the argument is not a valid address, returns nothing. This function is
+intended to aid in safely verifying address literals without having to deal
+with exceptions.
+
+
+<h3>Parameters</h3>
+<ul>
+
+ <li>
+ address: String containing a valid MAC address or existing luci.ip.cidr
+MAC address instance.
+ </li>
+
+</ul>
+
+
+
+
+<h3>Usage:</h3>
+<pre>mac = luci.ip.checkmac(luci.ip.new("00-11-22-cc-dd-ee")) -- "00:11:22:CC:DD:EE"
+mac = luci.ip.checkmac("00:11:22:cc:dd:ee") -- "00:11:22:CC:DD:EE"
+mac = luci.ip.checkmac("nonesense") -- nothing
+mac = luci.ip.checkmac(123) -- nothing
+mac = luci.ip.checkmac(nil) -- nothing
+mac = luci.ip.checkmac() -- nothing</pre>
+
+
+
+<h3>Return value:</h3>
+A string representing the given MAC address.
+
+
+
+<h3>See also:</h3>
+<ul>
+
+ <li><a href="#checkip4">
+ checkip4
+ </a>
+
+ <li><a href="#checkip6">
+ checkip6
+ </a>
+
</ul>
</dd>
@@ -787,7 +1069,7 @@ A neighbour entry is a table containing the following fields:
</tr>
<tr>
<td><code>mac</code></td>
- <td>String containing the associated MAC address</td>
+ <td>MAC address <code>luci.ip.cidr</code> instance</td>
</tr>
<tr>
<td><code>router</code></td>
@@ -905,8 +1187,8 @@ described below is returned, else an empty table.
</tr>
<tr>
<td><code>mac</code></td>
- <td>String containing the link local address of the device in
- dotted hex notation</td>
+ <td>MAC address <code>luci.ip.cidr</code> instance representing the device ethernet
+ address</td>
</tr>
</table>
diff --git a/documentation/api/modules/luci.util.html b/documentation/api/modules/luci.util.html
index 847230bbb..70d27d331 100644
--- a/documentation/api/modules/luci.util.html
+++ b/documentation/api/modules/luci.util.html
@@ -629,7 +629,7 @@ Cloned table value
<dd>
-Count the occurrences of given substring in given string.
+Count the occurrences of given substring in given string.
diff --git a/documentation/api/modules/nixio.README.html b/documentation/api/modules/nixio.README.html
index d8a17f78b..99e036b82 100644
--- a/documentation/api/modules/nixio.README.html
+++ b/documentation/api/modules/nixio.README.html
@@ -288,7 +288,7 @@
<br />In general all functions are namend and behave like their POSIX API
counterparts - where applicable - applying the following rules:
<ul>
- <li>Functions should be named like the underlying POSIX API function omitting
+ <li>Functions should be named like the underlying POSIX API function omitting
prefixes or suffixes - especially when placed in an object-context (
lockf -> File:lock, fsync -> File:sync, dup2 -> dup, ...)</li>
<li>If you are unclear about the behaviour of a function you should consult
@@ -296,10 +296,10 @@
<li>If the name is significantly different from the POSIX-function, the
underlying function(s) are stated in the documentation.</li>
<li>Parameters should reflect those of the C-API, buffer length arguments and
- by-reference parameters should be omitted for pratical purposes.</li>
+ by-reference parameters should be omitted for practical purposes.</li>
<li>If a C function accepts a bitfield as parameter, it should be translated
into lower case string flags representing the flags if the bitfield is the
- last parameter and also omitting prefixes or suffixes. (e.g. waitpid
+ last parameter and also omitting prefixes or suffixes. (e.g. waitpid
(pid, &s, WNOHANG | WUNTRACED) -> waitpid(pid, "nohang", "untraced"),
getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) ->
Socket:getopt("socket", "reuseaddr"), etc.) </li>
diff --git a/documentation/api/modules/nixio.UnifiedIO.html b/documentation/api/modules/nixio.UnifiedIO.html
index 171798084..700485dbe 100644
--- a/documentation/api/modules/nixio.UnifiedIO.html
+++ b/documentation/api/modules/nixio.UnifiedIO.html
@@ -326,7 +326,7 @@
<li>The blocksize given is only advisory and to be seen as an upper limit,
if an underlying read returns less bytes the chunk is nevertheless returned.
- <li>If the limit parameter is omitted, the iterator returns data
+ <li>If the limit parameter is omitted, the iterator returns data
until an end-of-file, end-of-stream, connection shutdown or similar happens.
<li>The iterator will not buffer so it is safe to mix with calls to read.
@@ -402,7 +402,7 @@ true
<li>This function uses the blocksource function of the source descriptor
and the sink function of the target descriptor.
- <li>If the limit parameter is omitted, data is copied
+ <li>If the limit parameter is omitted, data is copied
until an end-of-file, end-of-stream, connection shutdown or similar happens.
<li>If the descriptor is non-blocking the function may fail with EAGAIN.
@@ -461,7 +461,7 @@ true
blocksource function of the source descriptor and the sink function
of the target descriptor as a fallback mechanism.
- <li>If the limit parameter is omitted, data is copied
+ <li>If the limit parameter is omitted, data is copied
until an end-of-file, end-of-stream, connection shutdown or similar happens.
<li>If the descriptor is non-blocking the function may fail with EAGAIN.
@@ -584,7 +584,7 @@ boolean
you can pass "true" to the iterator which will flush the buffer
and return the bufferd data.
- <li>If the limit parameter is omitted, this function uses the nixio
+ <li>If the limit parameter is omitted, this function uses the nixio
buffersize (8192B by default).
<li>If the descriptor is non-blocking the iterator may fail with EAGAIN.
@@ -628,7 +628,7 @@ Line-based Iterator
<li>This function uses the low-level read function of the descriptor.
- <li>If the length parameter is omitted, this function returns all data
+ <li>If the length parameter is omitted, this function returns all data
that can be read before an end-of-file, end-of-stream, connection shutdown
or similar happens.
diff --git a/libs/luci-lib-ip/src/ip.c b/libs/luci-lib-ip/src/ip.c
index b91966c53..854a0c09c 100644
--- a/libs/luci-lib-ip/src/ip.c
+++ b/libs/luci-lib-ip/src/ip.c
@@ -1,5 +1,5 @@
/*
-Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
+Copyright 2015-2018 Jo-Philipp Wich <jo@mein.io>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -42,6 +42,16 @@ limitations under the License.
#define RTA_INT(x) (*(int *)RTA_DATA(x))
#define RTA_U32(x) (*(uint32_t *)RTA_DATA(x))
+#define AF_BITS(f) \
+ ((f) == AF_INET ? 32 : \
+ ((f) == AF_INET6 ? 128 : \
+ ((f) == AF_PACKET ? 48 : 0)))
+
+#define AF_BYTES(f) \
+ ((f) == AF_INET ? 4 : \
+ ((f) == AF_INET6 ? 16 : \
+ ((f) == AF_PACKET ? 6 : 0)))
+
static int hz = 0;
static struct nl_sock *sock = NULL;
@@ -49,11 +59,11 @@ typedef struct {
union {
struct in_addr v4;
struct in6_addr v6;
+ struct ether_addr mac;
+ uint8_t u8[16];
} addr;
- int len;
- int bits;
- int family;
- bool exact;
+ uint16_t family;
+ int16_t bits;
} cidr_t;
struct dump_filter {
@@ -70,6 +80,8 @@ struct dump_filter {
cidr_t src;
cidr_t dst;
struct ether_addr mac;
+ bool from_exact;
+ bool dst_exact;
};
struct dump_state {
@@ -95,29 +107,68 @@ static cidr_t *L_checkcidr (lua_State *L, int index, cidr_t *p)
return NULL;
}
-static bool parse_mask(int family, const char *mask, int *bits)
+static bool parse_mac(const char *mac, struct ether_addr *ea)
+{
+ unsigned long int n;
+ char *e, sep = 0;
+ int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ if (i > 0)
+ {
+ if (sep == 0 && (mac[0] == ':' || mac[0] == '-'))
+ sep = mac[0];
+
+ if (sep == 0 || mac[0] != sep)
+ return false;
+
+ mac++;
+ }
+
+ n = strtoul(mac, &e, 16);
+
+ if (n > 0xFF)
+ return false;
+
+ mac += (e - mac);
+ ea->ether_addr_octet[i] = n;
+ }
+
+ if (mac[0] != 0)
+ return false;
+
+ return true;
+}
+
+static bool parse_mask(int family, const char *mask, int16_t *bits)
{
char *e;
- struct in_addr m;
- struct in6_addr m6;
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ struct ether_addr mac;
+ uint8_t u8[16];
+ } m;
- if (family == AF_INET && inet_pton(AF_INET, mask, &m))
+ if (family == AF_INET && inet_pton(AF_INET, mask, &m.v4))
{
- for (*bits = 0, m.s_addr = ntohl(m.s_addr);
- *bits < 32 && (m.s_addr << *bits) & 0x80000000;
+ for (*bits = 0, m.v4.s_addr = ntohl(m.v4.s_addr);
+ *bits < AF_BITS(AF_INET) && (m.v4.s_addr << *bits) & 0x80000000;
++*bits);
}
- else if (family == AF_INET6 && inet_pton(AF_INET6, mask, &m6))
+ else if ((family == AF_INET6 && inet_pton(AF_INET6, mask, &m.v6)) ||
+ (family == AF_PACKET && parse_mac(mask, &m.mac)))
{
for (*bits = 0;
- *bits < 128 && (m6.s6_addr[*bits / 8] << (*bits % 8)) & 128;
+ *bits < AF_BITS(family) && (m.u8[*bits / 8] << (*bits % 8)) & 128;
++*bits);
}
else
{
*bits = strtoul(mask, &e, 10);
- if (e == mask || *e != 0 || *bits > ((family == AF_INET) ? 32 : 128))
+ if (e == mask || *e != 0 || *bits > AF_BITS(family))
return false;
}
@@ -127,7 +178,6 @@ static bool parse_mask(int family, const char *mask, int *bits)
static bool parse_cidr(const char *dest, cidr_t *pp)
{
char *p, buf[INET6_ADDRSTRLEN * 2 + 2];
- uint8_t bitlen = 0;
strncpy(buf, dest, sizeof(buf) - 1);
@@ -137,17 +187,11 @@ static bool parse_cidr(const char *dest, cidr_t *pp)
*p++ = 0;
if (inet_pton(AF_INET, buf, &pp->addr.v4))
- {
- bitlen = 32;
pp->family = AF_INET;
- pp->len = sizeof(struct in_addr);
- }
else if (inet_pton(AF_INET6, buf, &pp->addr.v6))
- {
- bitlen = 128;
pp->family = AF_INET6;
- pp->len = sizeof(struct in6_addr);
- }
+ else if (parse_mac(buf, &pp->addr.mac))
+ pp->family = AF_PACKET;
else
return false;
@@ -158,12 +202,45 @@ static bool parse_cidr(const char *dest, cidr_t *pp)
}
else
{
- pp->bits = bitlen;
+ pp->bits = AF_BITS(pp->family);
}
return true;
}
+static int format_cidr(lua_State *L, cidr_t *p)
+{
+ char buf[INET6_ADDRSTRLEN];
+
+ if (p->family == AF_PACKET)
+ {
+ snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X",
+ p->addr.mac.ether_addr_octet[0],
+ p->addr.mac.ether_addr_octet[1],
+ p->addr.mac.ether_addr_octet[2],
+ p->addr.mac.ether_addr_octet[3],
+ p->addr.mac.ether_addr_octet[4],
+ p->addr.mac.ether_addr_octet[5]);
+
+ if (p->bits < AF_BITS(AF_PACKET))
+ lua_pushfstring(L, "%s/%d", buf, p->bits);
+ else
+ lua_pushstring(L, buf);
+ }
+ else
+ {
+ if (p->bits < AF_BITS(p->family))
+ lua_pushfstring(L, "%s/%d",
+ inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)),
+ p->bits);
+ else
+ lua_pushstring(L,
+ inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)));
+ }
+
+ return 1;
+}
+
static int L_getint(lua_State *L, int index, const char *name)
{
int rv = 0;
@@ -220,17 +297,21 @@ static void L_setaddr(struct lua_State *L, const char *name,
if (family == AF_INET)
{
p->family = AF_INET;
- p->bits = (bits < 0) ? 32 : bits;
- p->len = sizeof(p->addr.v4);
+ p->bits = (bits < 0) ? AF_BITS(AF_INET) : bits;
p->addr.v4 = *(struct in_addr *)addr;
}
- else
+ else if (family == AF_INET6)
{
p->family = AF_INET6;
- p->bits = (bits < 0) ? 128 : bits;
- p->len = sizeof(p->addr.v6);
+ p->bits = (bits < 0) ? AF_BITS(AF_INET6) : bits;
p->addr.v6 = *(struct in6_addr *)addr;
}
+ else
+ {
+ p->family = AF_PACKET;
+ p->bits = (bits < 0) ? AF_BITS(AF_PACKET) : bits;
+ p->addr.mac = *(struct ether_addr *)addr;
+ }
luaL_getmetatable(L, LUCI_IP_CIDR);
lua_setmetatable(L, -2);
@@ -254,6 +335,7 @@ static void L_setdev(struct lua_State *L, const char *name,
static int L_checkbits(lua_State *L, int index, cidr_t *p)
{
+ int16_t s16;
int bits;
if (lua_gettop(L) < index || lua_isnil(L, index))
@@ -264,13 +346,15 @@ static int L_checkbits(lua_State *L, int index, cidr_t *p)
{
bits = lua_tointeger(L, index);
- if (bits < 0 || bits > ((p->family == AF_INET) ? 32 : 128))
+ if (bits < 0 || bits > AF_BITS(p->family))
return luaL_error(L, "Invalid prefix size");
}
else if (lua_type(L, index) == LUA_TSTRING)
{
- if (!parse_mask(p->family, lua_tostring(L, index), &bits))
+ if (!parse_mask(p->family, lua_tostring(L, index), &s16))
return luaL_error(L, "Invalid netmask format");
+
+ bits = s16;
}
else
{
@@ -293,20 +377,26 @@ static int _cidr_new(lua_State *L, int index, int family, bool mask)
if (family == AF_INET6)
{
cidr.family = AF_INET6;
- cidr.bits = 128;
- cidr.len = sizeof(cidr.addr.v6);
cidr.addr.v6.s6_addr[12] = n;
cidr.addr.v6.s6_addr[13] = (n >> 8);
cidr.addr.v6.s6_addr[14] = (n >> 16);
cidr.addr.v6.s6_addr[15] = (n >> 24);
}
- else
+ else if (family == AF_INET)
{
cidr.family = AF_INET;
- cidr.bits = 32;
- cidr.len = sizeof(cidr.addr.v4);
cidr.addr.v4.s_addr = n;
}
+ else
+ {
+ cidr.family = AF_PACKET;
+ cidr.addr.mac.ether_addr_octet[2] = n;
+ cidr.addr.mac.ether_addr_octet[3] = (n >> 8);
+ cidr.addr.mac.ether_addr_octet[4] = (n >> 16);
+ cidr.addr.mac.ether_addr_octet[5] = (n >> 24);
+ }
+
+ cidr.bits = AF_BITS(cidr.family);
}
else
{
@@ -346,6 +436,62 @@ static int cidr_ipv6(lua_State *L)
return _cidr_new(L, 1, AF_INET6, true);
}
+static int cidr_mac(lua_State *L)
+{
+ return _cidr_new(L, 1, AF_PACKET, true);
+}
+
+static int cidr_check(lua_State *L, int family)
+{
+ cidr_t cidr = { }, *cidrp;
+ const char *addr;
+
+ if (lua_type(L, 1) == LUA_TSTRING)
+ {
+ addr = lua_tostring(L, 1);
+
+ if (addr && parse_cidr(addr, &cidr) && cidr.family == family)
+ return format_cidr(L, &cidr);
+ }
+ else
+ {
+ cidrp = lua_touserdata(L, 1);
+
+ if (cidrp == NULL)
+ return 0;
+
+ if (!lua_getmetatable(L, 1))
+ return 0;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, LUCI_IP_CIDR);
+
+ if (!lua_rawequal(L, -1, -2))
+ cidrp = NULL;
+
+ lua_pop(L, 2);
+
+ if (cidrp != NULL && cidrp->family == family)
+ return format_cidr(L, cidrp);
+ }
+
+ return 0;
+}
+
+static int cidr_checkip4(lua_State *L)
+{
+ return cidr_check(L, AF_INET);
+}
+
+static int cidr_checkip6(lua_State *L)
+{
+ return cidr_check(L, AF_INET6);
+}
+
+static int cidr_checkmac(lua_State *L)
+{
+ return cidr_check(L, AF_PACKET);
+}
+
static int cidr_is4(lua_State *L)
{
cidr_t *p = L_checkcidr(L, 1, NULL);
@@ -424,6 +570,34 @@ static int cidr_is6linklocal(lua_State *L)
return 1;
}
+static int cidr_ismac(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, p->family == AF_PACKET);
+ return 1;
+}
+
+static int cidr_ismacmcast(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, (p->family == AF_PACKET &&
+ (p->addr.mac.ether_addr_octet[0] & 0x1)));
+
+ return 1;
+}
+
+static int cidr_ismaclocal(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, (p->family == AF_PACKET &&
+ (p->addr.mac.ether_addr_octet[0] & 0x2)));
+
+ return 1;
+}
+
static int _cidr_cmp(lua_State *L)
{
cidr_t *a = L_checkcidr(L, 1, NULL);
@@ -432,7 +606,7 @@ static int _cidr_cmp(lua_State *L)
if (a->family != b->family)
return (a->family - b->family);
- return memcmp(&a->addr.v6, &b->addr.v6, a->len);
+ return memcmp(&a->addr.v6, &b->addr.v6, AF_BYTES(a->family));
}
static int cidr_lower(lua_State *L)
@@ -475,24 +649,24 @@ static void _apply_mask(cidr_t *p, int bits, bool inv)
if (bits <= 0)
{
- memset(&p->addr.v6, inv * 0xFF, p->len);
+ memset(&p->addr.u8, inv * 0xFF, AF_BYTES(p->family));
}
- else if (p->family == AF_INET && bits <= 32)
+ else if (p->family == AF_INET && bits <= AF_BITS(AF_INET))
{
if (inv)
- p->addr.v4.s_addr |= ntohl((1 << (32 - bits)) - 1);
+ p->addr.v4.s_addr |= ntohl((1 << (AF_BITS(AF_INET) - bits)) - 1);
else
- p->addr.v4.s_addr &= ntohl(~((1 << (32 - bits)) - 1));
+ p->addr.v4.s_addr &= ntohl(~((1 << (AF_BITS(AF_INET) - bits)) - 1));
}
- else if (p->family == AF_INET6 && bits <= 128)
+ else if (bits <= AF_BITS(p->family))
{
- for (i = 0; i < sizeof(p->addr.v6.s6_addr); i++)
+ for (i = 0; i < AF_BYTES(p->family); i++)
{
b = (bits > 8) ? 8 : bits;
if (inv)
- p->addr.v6.s6_addr[i] |= ~((uint8_t)(0xFF << (8 - b)));
+ p->addr.u8[i] |= ~((uint8_t)(0xFF << (8 - b)));
else
- p->addr.v6.s6_addr[i] &= (uint8_t)(0xFF << (8 - b));
+ p->addr.u8[i] &= (uint8_t)(0xFF << (8 - b));
bits -= b;
}
}
@@ -507,7 +681,7 @@ static int cidr_network(lua_State *L)
return 0;
*p2 = *p1;
- p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ p2->bits = AF_BITS(p1->family);
_apply_mask(p2, bits, false);
luaL_getmetatable(L, LUCI_IP_CIDR);
@@ -524,7 +698,7 @@ static int cidr_host(lua_State *L)
return 0;
*p2 = *p1;
- p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ p2->bits = AF_BITS(p1->family);
luaL_getmetatable(L, LUCI_IP_CIDR);
lua_setmetatable(L, -2);
@@ -539,7 +713,7 @@ static int cidr_mask(lua_State *L)
if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
return 0;
- p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ p2->bits = AF_BITS(p1->family);
p2->family = p1->family;
memset(&p2->addr.v6.s6_addr, 0xFF, sizeof(p2->addr.v6.s6_addr));
@@ -556,14 +730,14 @@ static int cidr_broadcast(lua_State *L)
cidr_t *p2;
int bits = L_checkbits(L, 2, p1);
- if (p1->family == AF_INET6)
+ if (p1->family != AF_INET)
return 0;
if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
return 0;
*p2 = *p1;
- p2->bits = (p1->family == AF_INET) ? 32 : 128;
+ p2->bits = AF_BITS(AF_INET);
_apply_mask(p2, bits, true);
luaL_getmetatable(L, LUCI_IP_CIDR);
@@ -583,7 +757,7 @@ static int cidr_mapped4(lua_State *L)
return 0;
p2->family = AF_INET;
- p2->bits = (p1->bits > 32) ? 32 : p1->bits;
+ p2->bits = (p1->bits > AF_BITS(AF_INET)) ? AF_BITS(AF_INET) : p1->bits;
memcpy(&p2->addr.v4, p1->addr.v6.s6_addr + 12, sizeof(p2->addr.v4));
luaL_getmetatable(L, LUCI_IP_CIDR);
@@ -591,6 +765,72 @@ static int cidr_mapped4(lua_State *L)
return 1;
}
+static int cidr_tolinklocal(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+ int i;
+
+ if (p1->family != AF_PACKET)
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_INET6;
+ p2->bits = AF_BITS(AF_INET6);
+ p2->addr.u8[0] = 0xFE;
+ p2->addr.u8[1] = 0x80;
+ p2->addr.u8[8] = p1->addr.u8[0] ^ 0x02;
+ p2->addr.u8[9] = p1->addr.u8[1];
+ p2->addr.u8[10] = p1->addr.u8[2];
+ p2->addr.u8[11] = 0xFF;
+ p2->addr.u8[12] = 0xFE;
+ p2->addr.u8[13] = p1->addr.u8[3];
+ p2->addr.u8[14] = p1->addr.u8[4];
+ p2->addr.u8[15] = p1->addr.u8[5];
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_tomac(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+ int i;
+
+ if (p1->family != AF_INET6 ||
+ p1->addr.u8[0] != 0xFE ||
+ p1->addr.u8[1] != 0x80 ||
+ p1->addr.u8[2] != 0x00 ||
+ p1->addr.u8[3] != 0x00 ||
+ p1->addr.u8[4] != 0x00 ||
+ p1->addr.u8[5] != 0x00 ||
+ p1->addr.u8[6] != 0x00 ||
+ p1->addr.u8[7] != 0x00 ||
+ p1->addr.u8[11] != 0xFF ||
+ p1->addr.u8[12] != 0xFE)
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_PACKET;
+ p2->bits = AF_BITS(AF_PACKET);
+ p2->addr.u8[0] = p1->addr.u8[8] ^ 0x02;
+ p2->addr.u8[1] = p1->addr.u8[9];
+ p2->addr.u8[2] = p1->addr.u8[10];
+ p2->addr.u8[3] = p1->addr.u8[13];
+ p2->addr.u8[4] = p1->addr.u8[14];
+ p2->addr.u8[5] = p1->addr.u8[15];
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
static int cidr_contains(lua_State *L)
{
cidr_t *p1 = L_checkcidr(L, 1, NULL);
@@ -603,15 +843,15 @@ static int cidr_contains(lua_State *L)
_apply_mask(&a, p1->bits, false);
_apply_mask(&b, p1->bits, false);
- rv = !memcmp(&a.addr.v6, &b.addr.v6, a.len);
+ rv = !memcmp(&a.addr.v6, &b.addr.v6, AF_BYTES(a.family));
}
lua_pushboolean(L, rv);
return 1;
}
-#define S6_BYTE(a, i) \
- (a)->addr.v6.s6_addr[sizeof((a)->addr.v6.s6_addr) - (i) - 1]
+#define BYTE(a, i) \
+ (a)->addr.u8[AF_BYTES((a)->family) - (i) - 1]
static int _cidr_add_sub(lua_State *L, bool add)
{
@@ -625,45 +865,45 @@ static int _cidr_add_sub(lua_State *L, bool add)
if (p1->family == p2->family)
{
- if (p1->family == AF_INET6)
+ if (p1->family == AF_INET)
+ {
+ a = ntohl(p1->addr.v4.s_addr);
+ b = ntohl(p2->addr.v4.s_addr);
+
+ /* would over/underflow */
+ if ((add && (UINT_MAX - a) < b) || (!add && a < b))
+ {
+ r.addr.v4.s_addr = add * 0xFFFFFFFF;
+ ok = false;
+ }
+ else
+ {
+ r.addr.v4.s_addr = add ? htonl(a + b) : htonl(a - b);
+ }
+ }
+ else
{
- for (i = 0, carry = 0; i < sizeof(r.addr.v6.s6_addr); i++)
+ for (i = 0, carry = 0; i < AF_BYTES(p1->family); i++)
{
if (add)
{
- S6_BYTE(&r, i) = S6_BYTE(p1, i) + S6_BYTE(p2, i) + carry;
- carry = (S6_BYTE(p1, i) + S6_BYTE(p2, i) + carry) / 256;
+ BYTE(&r, i) = BYTE(p1, i) + BYTE(p2, i) + carry;
+ carry = (BYTE(p1, i) + BYTE(p2, i) + carry) / 256;
}
else
{
- S6_BYTE(&r, i) = (S6_BYTE(p1, i) - S6_BYTE(p2, i) - carry);
- carry = (S6_BYTE(p1, i) < (S6_BYTE(p2, i) + carry));
+ BYTE(&r, i) = (BYTE(p1, i) - BYTE(p2, i) - carry);
+ carry = (BYTE(p1, i) < (BYTE(p2, i) + carry));
}
}
/* would over/underflow */
if (carry)
{
- memset(&r.addr.v6, add * 0xFF, sizeof(r.addr.v6));
+ memset(&r.addr.u8, add * 0xFF, AF_BYTES(r.family));
ok = false;
}
}
- else
- {
- a = ntohl(p1->addr.v4.s_addr);
- b = ntohl(p2->addr.v4.s_addr);
-
- /* would over/underflow */
- if ((add && (UINT_MAX - a) < b) || (!add && a < b))
- {
- r.addr.v4.s_addr = add * 0xFFFFFFFF;
- ok = false;
- }
- else
- {
- r.addr.v4.s_addr = add ? htonl(a + b) : htonl(a - b);
- }
- }
}
else
{
@@ -705,22 +945,22 @@ static int cidr_minhost(lua_State *L)
_apply_mask(&r, r.bits, false);
- if (r.family == AF_INET6 && r.bits < 128)
+ if (r.family == AF_INET && r.bits < AF_BITS(AF_INET))
+ {
+ r.bits = AF_BITS(AF_INET);
+ r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) + 1);
+ }
+ else if (r.bits < AF_BITS(r.family))
{
- r.bits = 128;
+ r.bits = AF_BITS(r.family);
- for (i = 0, carry = 1; i < sizeof(r.addr.v6.s6_addr); i++)
+ for (i = 0, carry = 1; i < AF_BYTES(r.family); i++)
{
- rest = (S6_BYTE(&r, i) + carry) > 255;
- S6_BYTE(&r, i) += carry;
+ rest = (BYTE(&r, i) + carry) > 255;
+ BYTE(&r, i) += carry;
carry = rest;
}
}
- else if (r.family == AF_INET && r.bits < 32)
- {
- r.bits = 32;
- r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) + 1);
- }
if (!(p = lua_newuserdata(L, sizeof(*p))))
return 0;
@@ -739,14 +979,14 @@ static int cidr_maxhost(lua_State *L)
_apply_mask(&r, r.bits, true);
- if (r.family == AF_INET && r.bits < 32)
+ if (r.family == AF_INET && r.bits < AF_BITS(AF_INET))
{
- r.bits = 32;
+ r.bits = AF_BITS(AF_INET);
r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) - 1);
}
- else if (r.family == AF_INET6)
+ else
{
- r.bits = 128;
+ r.bits = AF_BITS(r.family);
}
if (!(p = lua_newuserdata(L, sizeof(*p))))
@@ -766,31 +1006,17 @@ static int cidr_gc (lua_State *L)
static int cidr_tostring (lua_State *L)
{
- char buf[INET6_ADDRSTRLEN];
cidr_t *p = L_checkcidr(L, 1, NULL);
-
- if ((p->family == AF_INET && p->bits < 32) ||
- (p->family == AF_INET6 && p->bits < 128))
- {
- lua_pushfstring(L, "%s/%d",
- inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)),
- p->bits);
- }
- else
- {
- lua_pushstring(L, inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)));
- }
-
- return 1;
+ return format_cidr(L, p);
}
/*
* route functions
*/
-static bool diff_prefix(int family, void *addr, int bits, cidr_t *p)
+static bool diff_prefix(int family, void *addr, int bits, bool exact, cidr_t *p)
{
- uint8_t i, b, r;
+ uint8_t i, b, r, *a;
uint32_t m;
if (!p->family)
@@ -799,28 +1025,27 @@ static bool diff_prefix(int family, void *addr, int bits, cidr_t *p)
if (!addr || p->family != family || p->bits > bits)
return true;
- if (family == AF_INET6)
+ if (family == AF_INET)
{
- for (i = 0, r = p->bits; i < sizeof(struct in6_addr); i++)
+ m = p->bits ? htonl(~((1 << (AF_BITS(AF_INET) - p->bits)) - 1)) : 0;
+
+ if ((((struct in_addr *)addr)->s_addr & m) != (p->addr.v4.s_addr & m))
+ return true;
+ }
+ else
+ {
+ for (i = 0, a = addr, r = p->bits; i < AF_BYTES(p->family); i++)
{
b = r ? (0xFF << (8 - ((r > 8) ? 8 : r))) : 0;
- if ((((struct in6_addr *)addr)->s6_addr[i] & b) !=
- (p->addr.v6.s6_addr[i] & b))
+ if ((a[i] & b) != (p->addr.u8[i] & b))
return true;
r -= ((r > 8) ? 8 : r);
}
}
- else
- {
- m = p->bits ? htonl(~((1 << (32 - p->bits)) - 1)) : 0;
- if ((((struct in_addr *)addr)->s_addr & m) != (p->addr.v4.s_addr & m))
- return true;
- }
-
- return (p->exact && p->bits != bits);
+ return (exact && p->bits != bits);
}
static int cb_dump_route(struct nl_msg *msg, void *arg)
@@ -848,7 +1073,7 @@ static int cb_dump_route(struct nl_msg *msg, void *arg)
dst = tb[RTA_DST] ? RTA_DATA(tb[RTA_DST]) : &def;
gw = tb[RTA_GATEWAY] ? RTA_DATA(tb[RTA_GATEWAY]) : NULL;
- bitlen = (rt->rtm_family == AF_INET6) ? 128 : 32;
+ bitlen = AF_BITS(rt->rtm_family);
if ((f->type && rt->rtm_type != f->type) ||
(f->family && rt->rtm_family != f->family) ||
@@ -857,10 +1082,14 @@ static int cb_dump_route(struct nl_msg *msg, void *arg)
(f->iif && iif != f->iif) ||
(f->oif && oif != f->oif) ||
(f->table && table != f->table) ||
- diff_prefix(rt->rtm_family, from, rt->rtm_src_len, &f->from) ||
- diff_prefix(rt->rtm_family, dst, rt->rtm_dst_len, &f->dst) ||
- diff_prefix(rt->rtm_family, gw, bitlen, &f->gw) ||
- diff_prefix(rt->rtm_family, src, bitlen, &f->src))
+ diff_prefix(rt->rtm_family, from, rt->rtm_src_len,
+ f->from_exact, &f->from) ||
+ diff_prefix(rt->rtm_family, dst, rt->rtm_dst_len,
+ f->dst_exact, &f->dst) ||
+ diff_prefix(rt->rtm_family, gw, bitlen,
+ false, &f->gw) ||
+ diff_prefix(rt->rtm_family, src, bitlen,
+ false, &f->src))
goto out;
if (s->callback)
@@ -988,7 +1217,8 @@ static int _route_dump(lua_State *L, struct dump_filter *filter)
nlmsg_append(msg, &rtm, sizeof(rtm), 0);
if (filter->get)
- nla_put(msg, RTA_DST, filter->dst.len, &filter->dst.addr.v6);
+ nla_put(msg, RTA_DST, AF_BYTES(filter->dst.family),
+ &filter->dst.addr.v6);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_route, &s);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &s);
@@ -1063,10 +1293,10 @@ static int route_dump(lua_State *L)
filter.dst = p;
if ((s = L_getstr(L, 1, "from_exact")) != NULL && parse_cidr(s, &p))
- filter.from = p, filter.from.exact = true;
+ filter.from = p, filter.from_exact = true;
if ((s = L_getstr(L, 1, "dest_exact")) != NULL && parse_cidr(s, &p))
- filter.dst = p, filter.dst.exact = true;
+ filter.dst = p, filter.dst_exact = true;
}
return _route_dump(L, &filter);
@@ -1107,12 +1337,12 @@ static int cb_dump_neigh(struct nl_msg *msg, void *arg)
mac = tb[NDA_LLADDR] ? RTA_DATA(tb[NDA_LLADDR]) : NULL;
dst = tb[NDA_DST] ? RTA_DATA(tb[NDA_DST]) : NULL;
- bitlen = (nd->ndm_family == AF_INET) ? 32 : 128;
+ bitlen = AF_BITS(nd->ndm_family);
if ((f->family && nd->ndm_family != f->family) ||
(f->iif && nd->ndm_ifindex != f->iif) ||
(f->type && !(f->type & nd->ndm_state)) ||
- diff_prefix(nd->ndm_family, dst, bitlen, &f->dst) ||
+ diff_prefix(nd->ndm_family, dst, bitlen, false, &f->dst) ||
diff_macaddr(mac, &f->mac))
goto out;
@@ -1140,15 +1370,7 @@ static int cb_dump_neigh(struct nl_msg *msg, void *arg)
L_setaddr(s->L, "dest", nd->ndm_family, dst, -1);
if (mac)
- {
- snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
- mac->ether_addr_octet[0], mac->ether_addr_octet[1],
- mac->ether_addr_octet[2], mac->ether_addr_octet[3],
- mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
-
- lua_pushstring(s->L, buf);
- lua_setfield(s->L, -2, "mac");
- }
+ L_setaddr(s->L, "mac", AF_PACKET, mac, -1);
s->index++;
@@ -1241,7 +1463,7 @@ out:
static int cb_dump_link(struct nl_msg *msg, void *arg)
{
- char *p, *addr, buf[48];
+ char buf[48];
struct dump_state *s = arg;
struct nlmsghdr *hdr = nlmsg_hdr(msg);
struct ifinfomsg *ifm = NLMSG_DATA(hdr);
@@ -1266,19 +1488,8 @@ static int cb_dump_link(struct nl_msg *msg, void *arg)
if (tb[IFLA_MASTER])
L_setdev(s->L, "master", tb[IFLA_MASTER]);
- if (tb[IFLA_ADDRESS])
- {
- len = nla_len(tb[IFLA_ADDRESS]);
- addr = nla_get_string(tb[IFLA_ADDRESS]);
-
- if ((len * 3) <= sizeof(buf))
- {
- for (p = buf, i = 0; i < len; i++)
- p += sprintf(p, "%s%02x", (i ? ":" : ""), (uint8_t)*addr++);
-
- L_setstr(s->L, "mac", buf);
- }
- }
+ if (tb[IFLA_ADDRESS] && nla_len(tb[IFLA_ADDRESS]) == AF_BYTES(AF_PACKET))
+ L_setaddr(s->L, "mac", AF_PACKET, nla_get_string(tb[IFLA_ADDRESS]), -1);
s->pending = 0;
return NL_SKIP;
@@ -1333,13 +1544,18 @@ static const luaL_reg ip_methods[] = {
{ "new", cidr_new },
{ "IPv4", cidr_ipv4 },
{ "IPv6", cidr_ipv6 },
+ { "MAC", cidr_mac },
+
+ { "checkip4", cidr_checkip4 },
+ { "checkip6", cidr_checkip6 },
+ { "checkmac", cidr_checkmac },
{ "route", route_get },
{ "routes", route_dump },
{ "neighbors", neighbor_dump },
- { "link", link_get },
+ { "link", link_get },
{ }
};
@@ -1351,6 +1567,9 @@ static const luaL_reg ip_cidr_methods[] = {
{ "is6", cidr_is6 },
{ "is6linklocal", cidr_is6linklocal },
{ "is6mapped4", cidr_is6mapped4 },
+ { "ismac", cidr_ismac },
+ { "ismaclocal", cidr_ismaclocal },
+ { "ismacmcast", cidr_ismacmcast },
{ "lower", cidr_lower },
{ "higher", cidr_higher },
{ "equal", cidr_equal },
@@ -1360,7 +1579,9 @@ static const luaL_reg ip_cidr_methods[] = {
{ "mask", cidr_mask },
{ "broadcast", cidr_broadcast },
{ "mapped4", cidr_mapped4 },
- { "contains", cidr_contains },
+ { "tomac", cidr_tomac },
+ { "tolinklocal", cidr_tolinklocal },
+ { "contains", cidr_contains },
{ "add", cidr_add },
{ "sub", cidr_sub },
{ "minhost", cidr_minhost },
diff --git a/libs/luci-lib-ip/src/ip.luadoc b/libs/luci-lib-ip/src/ip.luadoc
index e32ae72f4..b1ecae145 100644
--- a/libs/luci-lib-ip/src/ip.luadoc
+++ b/libs/luci-lib-ip/src/ip.luadoc
@@ -27,6 +27,7 @@ addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::")
addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask`
@see IPv4
@see IPv6
+@see MAC
]]
---[[
@@ -47,6 +48,7 @@ addr = luci.ip.IPv4("10.24.0.1/255.255.255.0")
addr = luci.ip.IPv4("10.24.0.1", "255.255.255.0") -- separate netmask
addr = luci.ip.IPv4("10.24.0.1/24", 16) -- override netmask`
@see IPv6
+@see MAC
]]
---[[
@@ -67,12 +69,112 @@ addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/ffff:ffff:ffff:ffff::")
addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::")
addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask`
@see IPv4
+@see MAC
]]
---[[
-Determine the route leading to the given destination.
+Construct a new MAC luci.ip.cidr instance.
+Throws an error if the given string does not represent a valid ethernet MAC
+address or if the given optional mask is of a different family.
@class function
@sort 4
+@name MAC
+@param address String containing a valid ethernet MAC address, optionally with
+prefix size (CIDR notation) or mask separated by slash.
+@param netmask String containing a valid MAC address mask or number
+containing a prefix size between `0` and `48` bit.
+Overrides mask embedded in the first argument if specified. (optional)
+@return A `luci.ip.cidr` object representing the given MAC address range.
+@usage `intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24")
+intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/FF:FF:FF:0:0:0")
+intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00", "FF:FF:FF:0:0:0")
+intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24", 48) -- override mask`
+@see IPv4
+@see IPv6
+]]
+
+---[[
+Verify an IPv4 address.
+
+Checks whether given argument is a preexisting luci.ip.cidr IPv4 address
+instance or a string literal convertible to an IPv4 address and returns a
+plain Lua string containing the canonical representation of the address.
+
+If the argument is not a valid address, returns nothing. This function is
+intended to aid in safely verifying address literals without having to deal
+with exceptions.
+@class function
+@sort 5
+@name checkip4
+@param address String containing a valid IPv4 address or existing
+luci.ip.cidr IPv4 instance.
+@return A string representing the given IPv4 address.
+@usage `ipv4 = luci.ip.checkip4(luci.ip.new("127.0.0.1")) -- "127.0.0.1"
+ipv4 = luci.ip.checkip4("127.0.0.1") -- "127.0.0.1"
+ipv4 = luci.ip.checkip4("nonesense") -- nothing
+ipv4 = luci.ip.checkip4(123) -- nothing
+ipv4 = luci.ip.checkip4(nil) -- nothing
+ipv4 = luci.ip.checkip4() -- nothing`
+@see checkip6
+@see checkmac
+]]
+
+---[[
+Verify an IPv6 address.
+
+Checks whether given argument is a preexisting luci.ip.cidr IPv6 address
+instance or a string literal convertible to an IPv6 address and returns a
+plain Lua string containing the canonical representation of the address.
+
+If the argument is not a valid address, returns nothing. This function is
+intended to aid in safely verifying address literals without having to deal
+with exceptions.
+@class function
+@sort 6
+@name checkip6
+@param address String containing a valid IPv6 address or existing
+luci.ip.cidr IPv6 instance.
+@return A string representing the given IPv6 address.
+@usage `ipv6 = luci.ip.checkip6(luci.ip.new("0:0:0:0:0:0:0:1")) -- "::1"
+ipv6 = luci.ip.checkip6("0:0:0:0:0:0:0:1") -- "::1"
+ipv6 = luci.ip.checkip6("nonesense") -- nothing
+ipv6 = luci.ip.checkip6(123) -- nothing
+ipv6 = luci.ip.checkip6(nil) -- nothing
+ipv6 = luci.ip.checkip6() -- nothing`
+@see checkip4
+@see checkmac
+]]
+
+---[[
+Verify an ethernet MAC address.
+
+Checks whether given argument is a preexisting luci.ip.cidr MAC address
+instance or a string literal convertible to an ethernet MAC and returns a
+plain Lua string containing the canonical representation of the address.
+
+If the argument is not a valid address, returns nothing. This function is
+intended to aid in safely verifying address literals without having to deal
+with exceptions.
+@class function
+@sort 7
+@name checkmac
+@param address String containing a valid MAC address or existing luci.ip.cidr
+MAC address instance.
+@return A string representing the given MAC address.
+@usage `mac = luci.ip.checkmac(luci.ip.new("00-11-22-cc-dd-ee")) -- "00:11:22:CC:DD:EE"
+mac = luci.ip.checkmac("00:11:22:cc:dd:ee") -- "00:11:22:CC:DD:EE"
+mac = luci.ip.checkmac("nonesense") -- nothing
+mac = luci.ip.checkmac(123) -- nothing
+mac = luci.ip.checkmac(nil) -- nothing
+mac = luci.ip.checkmac() -- nothing`
+@see checkip4
+@see checkip6
+]]
+
+---[[
+Determine the route leading to the given destination.
+@class function
+@sort 8
@name route
@param address A `luci.ip.cidr` instance or a string containing
a valid IPv4 or IPv6 range as specified by `luci.ip.new()`.
@@ -178,7 +280,7 @@ end`</li>
---[[
Fetch all routes, optionally matching the given criteria.
@class function
-@sort 5
+@sort 9
@name routes
@param filter <p>Table containing one or more of the possible filter
critera described below (optional)</p><table>
@@ -258,7 +360,7 @@ end`</li>
---[[
Fetches entries from the IPv4 ARP and IPv6 neighbour kernel table
@class function
-@sort 6
+@sort 10
@name neighbors
@param filter <p>Table containing one or more of the possible filter
critera described below (optional)</p><table>
@@ -306,7 +408,7 @@ A neighbour entry is a table containing the following fields:
</tr>
<tr>
<td>`mac`</td>
- <td>String containing the associated MAC address</td>
+ <td>MAC address `luci.ip.cidr` instance</td>
</tr>
<tr>
<td>`router`</td>
@@ -367,7 +469,7 @@ end)`</li>
---[[
Fetch basic device information
@class function
-@sort 7
+@sort 11
@name link
@param device String containing the network device to query
@return If the given interface is found, a table containing the fields
@@ -403,8 +505,8 @@ described below is returned, else an empty table.
</tr>
<tr>
<td>`mac`</td>
- <td>String containing the link local address of the device in
- dotted hex notation</td>
+ <td>MAC address `luci.ip.cidr` instance representing the device ethernet
+ address</td>
</tr>
</table>
@usage <ul>
@@ -430,6 +532,7 @@ Checks whether the CIDR instance is an IPv4 address range
@sort 1
@name cidr.is4
@see cidr.is6
+@see cidr.ismac
@return `true` if the CIDR is an IPv4 range, else `false`
]]
@@ -470,6 +573,7 @@ Checks whether the CIDR instance is an IPv6 address range
@sort 4
@name cidr.is6
@see cidr.is4
+@see cidr.ismac
@return `true` if the CIDR is an IPv6 range, else `false`
]]
@@ -502,13 +606,51 @@ end`
]]
---[[
+Checks whether the CIDR instance is an ethernet MAC address range
+
+@class function
+@sort 7
+@name cidr.ismac
+@see cidr.is4
+@see cidr.is6
+@return `true` if the CIDR is a MAC address range, else `false`
+]]
+
+---[[
+Checks whether the CIDR instance is a locally administered (LAA) MAC address
+
+@class function
+@sort 8
+@name cidr.ismaclocal
+@return `true` if the MAC address sets the locally administered bit.
+@usage `local mac = luci.ip.new("02:C0:FF:EE:00:01")
+if mac:ismaclocal() then
+ print("Is an LAA MAC address")
+end`
+]]
+
+---[[
+Checks whether the CIDR instance is a multicast MAC address
+
+@class function
+@sort 9
+@name cidr.ismacmcast
+@return `true` if the MAC address sets the multicast bit.
+@usage `local mac = luci.ip.new("01:00:5E:7F:00:10")
+if addr:ismacmcast() then
+ print("Is a multicast MAC address")
+end`
+]]
+
+---[[
Checks whether this CIDR instance is lower than the given argument.
The comparisation follows these rules:
-<ul><li>An IPv4 address is always lower than an IPv6 address</li>
+<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses
+are considered lower than MAC addresses</li>
<li>Prefix sizes are ignored</li></ul>
@class function
-@sort 7
+@sort 10
@name cidr.lower
@param addr A `luci.ip.cidr` instance or a string convertable by
`luci.ip.new()` to compare against.
@@ -518,7 +660,8 @@ The comparisation follows these rules:
print(addr:lower(addr)) -- false
print(addr:lower("10.10.10.10/24")) -- false
print(addr:lower(luci.ip.new("::1"))) -- true
-print(addr:lower(luci.ip.new("192.168.200.1"))) -- true`
+print(addr:lower(luci.ip.new("192.168.200.1"))) -- true
+print(addr:lower(luci.ip.new("00:14:22:01:23:45"))) -- true`
@see cidr.higher
@see cidr.equal
]]
@@ -526,11 +669,12 @@ print(addr:lower(luci.ip.new("192.168.200.1"))) -- true`
---[[
Checks whether this CIDR instance is higher than the given argument.
The comparisation follows these rules:
-<ul><li>An IPv4 address is always lower than an IPv6 address</li>
+<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses
+are considered lower than MAC addresses</li>
<li>Prefix sizes are ignored</li></ul>
@class function
-@sort 8
+@sort 11
@name cidr.higher
@param addr A `luci.ip.cidr` instance or a string convertable by
`luci.ip.new()` to compare against.
@@ -540,7 +684,8 @@ The comparisation follows these rules:
print(addr:higher(addr)) -- false
print(addr:higher("10.10.10.10/24")) -- true
print(addr:higher(luci.ip.new("::1"))) -- false
-print(addr:higher(luci.ip.new("192.168.200.1"))) -- false`
+print(addr:higher(luci.ip.new("192.168.200.1"))) -- false
+print(addr:higher(luci.ip.new("00:14:22:01:23:45"))) -- false`
@see cidr.lower
@see cidr.equal
]]
@@ -549,7 +694,7 @@ print(addr:higher(luci.ip.new("192.168.200.1"))) -- false`
Checks whether this CIDR instance is equal to the given argument.
@class function
-@sort 9
+@sort 12
@name cidr.equal
@param addr A `luci.ip.cidr` instance or a string convertable by
`luci.ip.new()` to compare against.
@@ -562,7 +707,11 @@ print(addr:equal(luci.ip.new("::1"))) -- false
local addr6 = luci.ip.new("::1")
print(addr6:equal("0:0:0:0:0:0:0:1/64")) -- true
-print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false`
+print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false
+
+local mac = luci.ip.new("00:14:22:01:23:45")
+print(mac:equal("0:14:22:1:23:45")) -- true
+print(mac:equal(luci.ip.new("01:23:45:67:89:AB")) -- false`
@see cidr.lower
@see cidr.higher
]]
@@ -573,11 +722,11 @@ If the optional mask parameter is given, the prefix size of this CIDR is altered
else the current prefix size is returned.
@class function
-@sort 10
+@sort 13
@name cidr.prefix
@param mask Either a number containing the number of bits (`0..32`
- for IPv4, `0..128` for IPv6) or a string containing a valid
- netmask (optional)
+ for IPv4, `0..128` for IPv6 or `0..48` for MAC addresses) or a string
+ containing a valid netmask (optional)
@return Bit count of the current prefix size
@usage `local range = luci.ip.new("192.168.1.1/255.255.255.0")
print(range:prefix()) -- 24
@@ -597,11 +746,11 @@ with all host parts masked out. The used prefix size can be overridden by the
optional mask parameter.
@class function
-@sort 11
+@sort 14
@name cidr.network
@param mask Either a number containing the number of bits (`0..32`
- for IPv4, `0..128` for IPv6) or a string containing a valid
- netmask (optional)
+ for IPv4, `0..128` for IPv6 or `0..48` for MAC addresses) or a string
+ containing a valid netmask (optional)
@return CIDR instance representing the network address
@usage `local range = luci.ip.new("192.168.62.243/255.255.0.0")
print(range:network()) -- "192.168.0.0"
@@ -616,10 +765,10 @@ print(range6:network()) -- "fd9b:62b3:9cc5::"`
Derive host address of CIDR instance.
This function essentially constructs a copy of this CIDR with the prefix size
-set to `32` for IPv4 and `128` for IPv6.
+set to `32` for IPv4, `128` for IPv6 or `48` for MAC addresses.
@class function
-@sort 12
+@sort 15
@name cidr.host
@return CIDR instance representing the host address
@usage `local range = luci.ip.new("172.19.37.45/16")
@@ -634,11 +783,11 @@ Constructs a CIDR instance representing the netmask of this instance. The used
prefix size can be overridden by the optional mask parameter.
@class function
-@sort 13
+@sort 16
@name cidr.mask
@param mask Either a number containing the number of bits (`0..32`
- for IPv4, `0..128` for IPv6) or a string containing a valid
- netmask (optional)
+ for IPv4, `0..128` for IPv6 or `0..48` for MAC addresses) or a string
+ containing a valid netmask (optional)
@return CIDR instance representing the netmask
@usage `local range = luci.ip.new("172.19.37.45/16")
print(range:mask()) -- "255.255.0.0"
@@ -652,15 +801,14 @@ Derive broadcast address of CIDR instance.
Constructs a CIDR instance representing the broadcast address of this instance.
The used prefix size can be overridden by the optional mask parameter.
-This function has no effect on IPv6 instances, it will return nothing in this
-case.
+This function has no effect on IPv6 or MAC address instances, it will return
+nothing in this case.
@class function
-@sort 14
+@sort 17
@name cidr.broadcast
-@param mask Either a number containing the number of bits (`0..32`
- for IPv4, `0..128` for IPv6) or a string containing a valid
- netmask (optional)
+@param mask Either a number containing the number of bits (`0..32` for IPv4) or
+ a string containing a valid netmask (optional)
@return Return a new CIDR instance representing the broadcast address if this
instance is an IPv4 range, else return nothing.
@usage `local range = luci.ip.new("172.19.37.45/16")
@@ -675,11 +823,11 @@ Derive mapped IPv4 address of CIDR instance.
Constructs a CIDR instance representing the IPv4 address of the IPv6 mapped
IPv4 address in this instance.
-This function has no effect on IPv4 instances or IPv6 instances which are not a
-mapped address, it will return nothing in this case.
+This function has no effect on IPv4 instances, MAC address instances or IPv6
+instances which are not a mapped address, it will return nothing in this case.
@class function
-@sort 15
+@sort 18
@name cidr.mapped4
@return Return a new CIDR instance representing the IPv4 address if this
instance is an IPv6 mapped IPv4 address, else return nothing.
@@ -688,10 +836,46 @@ print(addr:mapped4()) -- "172.16.19.1"`
]]
---[[
+Derive MAC address of IPv6 link local CIDR instance.
+
+Constructs a CIDR instance representing the MAC address contained in the IPv6
+link local address of this instance.
+
+This function has no effect on IPv4 instances, MAC address instances or IPv6
+instances which are not a link local address, it will return nothing in this
+case.
+
+@class function
+@sort 19
+@name cidr.tomac
+@return Return a new CIDR instance representing the MAC address if this
+ instance is an IPv6 link local address, else return nothing.
+@usage `local addr = luci.ip.new("fe80::6666:b3ff:fe47:e1b9")
+print(addr:tomac()) -- "64:66:B3:47:E1:B9"`
+]]
+
+---[[
+Derive IPv6 link local address from MAC address CIDR instance.
+
+Constructs a CIDR instance representing the IPv6 link local address of the
+MAC address represented by this instance.
+
+This function has no effect on IPv4 instances or IPv6 instances, it will return
+nothing in this case.
+
+@class function
+@sort 20
+@name cidr.tolinklocal
+@return Return a new CIDR instance representing the IPv6 link local address.
+@usage `local mac = luci.ip.new("64:66:B3:47:E1:B9")
+print(mac:tolinklocal()) -- "fe80::6666:b3ff:fe47:e1b9"`
+]]
+
+---[[
Test whether CIDR contains given range.
@class function
-@sort 16
+@sort 21
@name cidr.contains
@param addr A `luci.ip.cidr` instance or a string convertable by
`luci.ip.new()` to test.
@@ -704,7 +888,11 @@ print(range:contains("10.0.0.0/8")) -- false
local range6 = luci.ip.new("fe80::/10")
print(range6:contains("fe80::221:63f:fe75:aa17/64")) -- true
-print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false`
+print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false
+
+local intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24")
+print(intel_macs:contains("C0:B6:F9:A3:C:11")) -- true
+print(intel_macs:contains("64:66:B3:47:E1:B9")) -- false`
]]
---[[
@@ -712,7 +900,7 @@ Add given amount to CIDR instance. If the result would overflow the maximum
address space, the result is set to the highest possible address.
@class function
-@sort 17
+@sort 22
@name cidr.add
@param amount A numeric value between 0 and 0xFFFFFFFF, a
`luci.ip.cidr` instance or a string convertable by
@@ -726,32 +914,42 @@ address space, the result is set to the highest possible address.
this instance plus the added amount or the highest possible address if
the addition overflowed the available address space.</li></ul>
@usage `local addr = luci.ip.new("192.168.1.1/24")
-print(addr:add(250)) -- "192.168.1.251/24"
-print(addr:add("0.0.99.0")) -- "192.168.100.1/24"
+print(addr:add(250)) -- "192.168.1.251/24"
+print(addr:add("0.0.99.0")) -- "192.168.100.1/24"
-addr:add(256, true) -- true
-print(addr) -- "192.168.2.1/24
+addr:add(256, true) -- true
+print(addr) -- "192.168.2.1/24
-addr:add("255.0.0.0", true) -- false (overflow)
-print(addr) -- "255.255.255.255/24
+addr:add("255.0.0.0", true) -- false (overflow)
+print(addr) -- "255.255.255.255/24
local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64")
-print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64"
-print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64"
+print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64"
+print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64"
+
+addr6:add(256, true) -- true
+print(addr6) -- "fe80::221:63f:fe75:ab17/64
+
+addr6:add("ffff::", true) -- false (overflow)
+print(addr6) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"
-addr:add(256, true) -- true
-print(addr) -- "fe80::221:63f:fe75:ab17/64
+local mac = luci.ip.new("00:14:22:01:23:45")
+print(mac:add(256)) -- "00:14:22:01:24:45"
+print(mac:add("0:0:0:0:FF:0") -- "00:14:22:02:22:45"
-addr:add("ffff::", true) -- false (overflow)
-print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"`
+mac:add(256, true) -- true
+print(mac) -- "00:14:22:01:24:45"
+
+mac:add("FF:FF:0:0:0:0", true) -- false (overflow)
+print(mac) -- "FF:FF:FF:FF:FF:FF"`
]]
---[[
-Substract given amount from CIDR instance. If the result would under, the lowest
+Subtract given amount from CIDR instance. If the result would under, the lowest
possible address is returned.
@class function
-@sort 18
+@sort 23
@name cidr.sub
@param amount A numeric value between 0 and 0xFFFFFFFF, a
`luci.ip.cidr` instance or a string convertable by
@@ -759,11 +957,11 @@ possible address is returned.
@param inplace If `true`, modify this instance instead of returning
a new derived CIDR instance.
@return <ul>
- <li>When substracting inplace: Return `true` if the substraction
- succeded or `false` when the substraction underflowed.</li>
+ <li>When subtracting inplace: Return `true` if the subtraction
+ succeeded or `false` when the subtraction underflowed.</li>
<li>When deriving new CIDR: Return new instance representing the value of
- this instance minus the substracted amount or the lowest address if
- the substraction underflowed.</li></ul>
+ this instance minus the subtracted amount or the lowest address if
+ the subtraction underflowed.</li></ul>
@usage `local addr = luci.ip.new("192.168.1.1/24")
print(addr:sub(256)) -- "192.168.0.1/24"
print(addr:sub("0.168.0.0")) -- "192.0.1.1/24"
@@ -782,14 +980,24 @@ addr:sub(256, true) -- true
print(addr) -- "fe80::221:63f:fe75:a917/64"
addr:sub("ffff::", true) -- false (underflow)
-print(addr) -- "::/64"`
+print(addr) -- "::/64"
+
+local mac = luci.ip.new("00:14:22:01:23:45")
+print(mac:sub(256)) -- "00:14:22:01:22:45"
+print(mac:sub("0:0:0:0:FF:0") -- "00:14:22:00:24:45"
+
+mac:sub(256, true) -- true
+print(mac) -- "00:14:22:01:22:45"
+
+mac:sub("FF:FF:0:0:0:0", true) -- false (overflow)
+print(mac) -- "00:00:00:00:00:00"`
]]
---[[
Calculate the lowest possible host address within this CIDR instance.
@class function
-@sort 19
+@sort 24
@name cidr.minhost
@return Returns a new CIDR instance representing the lowest host address
within this range.
@@ -797,14 +1005,17 @@ Calculate the lowest possible host address within this CIDR instance.
print(addr:minhost()) -- "192.168.123.1"
local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
-print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"`
+print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"
+
+local mac = luci.ip.new("00:14:22:01:22:45/32")
+print(mac:minhost()) -- "00:14:22:01:00:01"`
]]
---[[
Calculate the highest possible host address within this CIDR instance.
@class function
-@sort 20
+@sort 25
@name cidr.maxhost
@return Returns a new CIDR instance representing the highest host address
within this range.
@@ -812,20 +1023,24 @@ Calculate the highest possible host address within this CIDR instance.
print(addr:maxhost()) -- "192.168.123.254" (.255 is broadcast)
local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
-print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"`
+print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"
+
+local mac = luci.ip.new("00:14:22:01:22:45/32")
+print(mac:maxhost()) -- "00:14:22:01:FF:FF"`
]]
---[[
Convert CIDR instance into string representation.
-If the prefix size of instance is less than 32 for IPv4 or 128 for IPv6, the
-address is returned in the form "address/prefix" otherwise just "address".
+If the prefix size of instance is less than 32 for IPv4, 128 for IPv6 or 48 for
+MACs, the address is returned in the form "address/prefix" otherwise just
+"address".
It is usually not required to call this function directly as CIDR objects
define it as __tostring function in the associated metatable.
@class function
-@sort 21
+@sort 26
@name cidr.string
@return Returns a string representing the range or address of this CIDR instance
]]
diff --git a/libs/luci-lib-nixio/docsrc/README.lua b/libs/luci-lib-nixio/docsrc/README.lua
index ee3e3a216..9860cf091 100644
--- a/libs/luci-lib-nixio/docsrc/README.lua
+++ b/libs/luci-lib-nixio/docsrc/README.lua
@@ -33,7 +33,7 @@ module "nixio.README"
-- <br />In general all functions are namend and behave like their POSIX API
-- counterparts - where applicable - applying the following rules:
-- <ul>
--- <li>Functions should be named like the underlying POSIX API function ommiting
+-- <li>Functions should be named like the underlying POSIX API function omitting
-- prefixes or suffixes - especially when placed in an object-context (
-- lockf -> File:lock, fsync -> File:sync, dup2 -> dup, ...)</li>
-- <li>If you are unclear about the behaviour of a function you should consult
@@ -41,10 +41,10 @@ module "nixio.README"
-- <li>If the name is significantly different from the POSIX-function, the
-- underlying function(s) are stated in the documentation.</li>
-- <li>Parameters should reflect those of the C-API, buffer length arguments and
--- by-reference parameters should be ommitted for pratical purposes.</li>
+-- by-reference parameters should be omitted for practical purposes.</li>
-- <li>If a C function accepts a bitfield as parameter, it should be translated
-- into lower case string flags representing the flags if the bitfield is the
--- last parameter and also ommiting prefixes or suffixes. (e.g. waitpid
+-- last parameter and also omitting prefixes or suffixes. (e.g. waitpid
-- (pid, &s, WNOHANG | WUNTRACED) -> waitpid(pid, "nohang", "untraced"),
-- getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) ->
-- Socket:getopt("socket", "reuseaddr"), etc.) </li>
diff --git a/libs/luci-lib-nixio/docsrc/nixio.Socket.lua b/libs/luci-lib-nixio/docsrc/nixio.Socket.lua
index 7123393bf..c970534ed 100644
--- a/libs/luci-lib-nixio/docsrc/nixio.Socket.lua
+++ b/libs/luci-lib-nixio/docsrc/nixio.Socket.lua
@@ -71,7 +71,7 @@ module "nixio.Socket"
--- Send a message on the socket.
-- This function is identical to sendto except for the missing destination
--- paramters. See the sendto description for a detailed description.
+-- parameters. See the sendto description for a detailed description.
-- @class function
-- @name Socket.send
-- @param buffer Buffer holding the data to be written.
@@ -167,4 +167,4 @@ module "nixio.Socket"
-- "mtu" (IP, IPv6), "hdrincl" (IP), "multicast_ttl" (IP), "multicast_loop"
-- (IP, IPv6), "multicast_if" (IP, IPv6), "v6only" (IPv6), "multicast_hops"
-- (IPv6), "add_membership" (IP, IPv6), "drop_membership" (IP, IPv6)]
--- @return Value \ No newline at end of file
+-- @return Value
diff --git a/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua b/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua
index 6e407ff2c..6d1d5ea8c 100644
--- a/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua
+++ b/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua
@@ -24,15 +24,15 @@ module "nixio.UnifiedIO"
-- @class function
-- @name UnifiedIO.readall
-- @usage This function uses the low-level read function of the descriptor.
--- @usage If the length parameter is ommited, this function returns all data
+-- @usage If the length parameter is omitted, this function returns all data
-- that can be read before an end-of-file, end-of-stream, connection shutdown
-- or similar happens.
-- @usage If the descriptor is non-blocking this function may fail with EAGAIN.
-- @param length Bytes to read (optional)
--- @return data that was successfully read if no error occured
+-- @return data that was successfully read if no error occurred
-- @return - reserved for error code -
-- @return - reserved for error message -
--- @return data that was successfully read even if an error occured
+-- @return data that was successfully read even if an error occurred
--- Write a block of data and wait until all data is written.
-- @class function
@@ -40,10 +40,10 @@ module "nixio.UnifiedIO"
-- @usage This function uses the low-level write function of the descriptor.
-- @usage If the descriptor is non-blocking this function may fail with EAGAIN.
-- @param block Bytes to write
--- @return bytes that were successfully written if no error occured
+-- @return bytes that were successfully written if no error occurred
-- @return - reserved for error code -
-- @return - reserved for error message -
--- @return bytes that were successfully written even if an error occured
+-- @return bytes that were successfully written even if an error occurred
--- Create a line-based iterator.
-- Lines may end with either \n or \r\n, these control chars are not included
@@ -56,7 +56,7 @@ module "nixio.UnifiedIO"
-- to stop reading line-based and want to use the read(all) functions instead
-- you can pass "true" to the iterator which will flush the buffer
-- and return the bufferd data.
--- @usage If the limit parameter is ommited, this function uses the nixio
+-- @usage If the limit parameter is omitted, this function uses the nixio
-- buffersize (8192B by default).
-- @usage If the descriptor is non-blocking the iterator may fail with EAGAIN.
-- @usage The iterator can be used as an LTN12 source.
@@ -69,7 +69,7 @@ module "nixio.UnifiedIO"
-- @usage This function uses the low-level read function of the descriptor.
-- @usage The blocksize given is only advisory and to be seen as an upper limit,
-- if an underlying read returns less bytes the chunk is nevertheless returned.
--- @usage If the limit parameter is ommited, the iterator returns data
+-- @usage If the limit parameter is omitted, the iterator returns data
-- until an end-of-file, end-of-stream, connection shutdown or similar happens.
-- @usage The iterator will not buffer so it is safe to mix with calls to read.
-- @usage If the descriptor is non-blocking the iterator may fail with EAGAIN.
@@ -94,15 +94,15 @@ module "nixio.UnifiedIO"
-- @name UnifiedIO.copy
-- @usage This function uses the blocksource function of the source descriptor
-- and the sink function of the target descriptor.
--- @usage If the limit parameter is ommited, data is copied
+-- @usage If the limit parameter is omitted, data is copied
-- until an end-of-file, end-of-stream, connection shutdown or similar happens.
-- @usage If the descriptor is non-blocking the function may fail with EAGAIN.
-- @param fdout Target Descriptor
-- @param size Bytes to copy (optional)
--- @return bytes that were successfully written if no error occured
+-- @return bytes that were successfully written if no error occurred
-- @return - reserved for error code -
-- @return - reserved for error message -
--- @return bytes that were successfully written even if an error occured
+-- @return bytes that were successfully written even if an error occurred
--- Copy data from the current descriptor to another one using kernel-space
-- copying if possible.
@@ -111,19 +111,19 @@ module "nixio.UnifiedIO"
-- @usage This function uses the sendfile() syscall to copy the data or the
-- blocksource function of the source descriptor and the sink function
-- of the target descriptor as a fallback mechanism.
--- @usage If the limit parameter is ommited, data is copied
+-- @usage If the limit parameter is omitted, data is copied
-- until an end-of-file, end-of-stream, connection shutdown or similar happens.
-- @usage If the descriptor is non-blocking the function may fail with EAGAIN.
-- @param fdout Target Descriptor
-- @param size Bytes to copy (optional)
--- @return bytes that were successfully written if no error occured
+-- @return bytes that were successfully written if no error occurred
-- @return - reserved for error code -
-- @return - reserved for error message -
--- @return bytes that were successfully written even if an error occured
+-- @return bytes that were successfully written even if an error occurred
--- Close the descriptor.
-- @class function
-- @name UnifiedIO.close
-- @usage If the descriptor is a TLS-socket the underlying descriptor is
-- closed without touching the TLS connection.
--- @return true \ No newline at end of file
+-- @return true
diff --git a/libs/luci-lib-nixio/docsrc/nixio.fs.lua b/libs/luci-lib-nixio/docsrc/nixio.fs.lua
index 5bfd7a6b7..ef495f260 100644
--- a/libs/luci-lib-nixio/docsrc/nixio.fs.lua
+++ b/libs/luci-lib-nixio/docsrc/nixio.fs.lua
@@ -47,7 +47,7 @@ module "nixio.fs"
-- @name nixio.fs.rename
-- @param src Source path
-- @param dest Destination path
--- @usage It is normally not possible to rename files accross filesystems.
+-- @usage It is normally not possible to rename files across filesystems.
-- @return true
--- Remove an empty directory.
@@ -262,4 +262,4 @@ module "nixio.fs"
-- omit the basename even if source and destination basename are equal.
-- @param src Source path
-- @param dest Destination path
--- @return true \ No newline at end of file
+-- @return true
diff --git a/libs/luci-lib-nixio/docsrc/nixio.lua b/libs/luci-lib-nixio/docsrc/nixio.lua
index 1b434d76d..1a0d69a05 100644
--- a/libs/luci-lib-nixio/docsrc/nixio.lua
+++ b/libs/luci-lib-nixio/docsrc/nixio.lua
@@ -118,7 +118,7 @@ module "nixio"
-- @param flag1 First Flag ["append", "creat", "excl", "nonblock", "ndelay",
-- "sync", "trunc", "rdonly", "wronly", "rdwr"]
-- @param ... More Flags [-"-]
--- @return flag to be used as second paramter to open
+-- @return flag to be used as second parameter to open
--- Duplicate a file descriptor.
-- @class function
@@ -167,7 +167,7 @@ module "nixio"
--- Wait for some event on a file descriptor.
-- poll() sets the revents-field of the tables provided by fds to a bitfield
--- indicating the events that occured.
+-- indicating the events that occurred.
-- @class function
-- @usage This function works in-place on the provided table and only
-- writes the revents field, you can use other fields on your demand.
@@ -303,7 +303,7 @@ module "nixio"
--- Set or unset a environment variable.
-- @class function
-- @name nixio.setenv
--- @usage The environment variable will be unset if value is ommited.
+-- @usage The environment variable will be unset if value is omitted.
-- @param variable Variable
-- @param value Value (optional)
-- @return true
diff --git a/modules/luci-base/luasrc/cbi/datatypes.lua b/modules/luci-base/luasrc/cbi/datatypes.lua
index a7e02f350..55cdf8a74 100644
--- a/modules/luci-base/luasrc/cbi/datatypes.lua
+++ b/modules/luci-base/luasrc/cbi/datatypes.lua
@@ -196,23 +196,7 @@ function portrange(val)
end
function macaddr(val)
- if val and val:match(
- "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
- "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
- ) then
- local parts = util.split( val, ":" )
-
- for i = 1,6 do
- parts[i] = tonumber( parts[i], 16 )
- if parts[i] < 0 or parts[i] > 255 then
- return false
- end
- end
-
- return true
- end
-
- return false
+ return ip.checkmac(val) and true or false
end
function hostname(val)
diff --git a/modules/luci-base/luasrc/http/protocol.luadoc b/modules/luci-base/luasrc/http/protocol.luadoc
index 67a60d9e7..19a0a3419 100644
--- a/modules/luci-base/luasrc/http/protocol.luadoc
+++ b/modules/luci-base/luasrc/http/protocol.luadoc
@@ -69,7 +69,7 @@ data line by line with the trailing \r\n stripped of.
Decode a mime encoded http message body with multipart/form-data
Content-Type. Stores all extracted data associated with its parameter name
-in the params table withing the given message object. Multiple parameter
+in the params table within the given message object. Multiple parameter
values are stored as tables, ordinary ones as strings.
If an optional file callback function is given then it is feeded with the
file contents chunk by chunk and only the extracted file name is stored
@@ -92,7 +92,7 @@ with three arguments:
Decode an urlencoded http message body with application/x-www-urlencoded
Content-Type. Stores all extracted data associated with its parameter name
-in the params table withing the given message object. Multiple parameter
+in the params table within the given message object. Multiple parameter
values are stored as tables, ordinary ones as strings.
@class function
@name urldecode_message_body
diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua
index 9ea8e369d..056fc67b1 100644
--- a/modules/luci-base/luasrc/model/network.lua
+++ b/modules/luci-base/luasrc/model/network.lua
@@ -330,7 +330,7 @@ function init(cursor)
if i.family == "packet" then
_interfaces[name].flags = i.flags
_interfaces[name].stats = i.data
- _interfaces[name].macaddr = i.addr
+ _interfaces[name].macaddr = ipc.checkmac(i.addr)
elseif i.family == "inet" then
_interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
elseif i.family == "inet6" then
@@ -543,6 +543,9 @@ end
function del_network(self, n)
local r = _uci:delete("network", n)
if r then
+ _uci:delete_all("luci", "ifstate",
+ function(s) return (s.interface == n) end)
+
_uci:delete_all("network", "alias",
function(s) return (s.interface == n) end)
@@ -998,7 +1001,10 @@ function protocol.ip6addrs(self)
if type(addrs) == "table" then
for n, addr in ipairs(addrs) do
- if type(addr["local-address"]) == "table" then
+ if type(addr["local-address"]) == "table" and
+ type(addr["local-address"].mask) == "number" and
+ type(addr["local-address"].address) == "string"
+ then
rv[#rv+1] = "%s/%d" %{
addr["local-address"].address,
addr["local-address"].mask
@@ -1227,8 +1233,7 @@ function interface.name(self)
end
function interface.mac(self)
- local mac = self:_ubus("macaddr")
- return mac and mac:upper()
+ return ipc.checkmac(self:_ubus("macaddr"))
end
function interface.ipaddrs(self)
diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-base/luasrc/sys.lua
index 84c747f2b..12b20e4c3 100644
--- a/modules/luci-base/luasrc/sys.lua
+++ b/modules/luci-base/luasrc/sys.lua
@@ -138,17 +138,22 @@ local function _nethints(what, callback)
luci.ip.neighbors(nil, function(neigh)
if neigh.mac and neigh.family == 4 then
- _add(what, neigh.mac:upper(), neigh.dest:string(), nil, nil)
+ _add(what, neigh.mac:string(), neigh.dest:string(), nil, nil)
elseif neigh.mac and neigh.family == 6 then
- _add(what, neigh.mac:upper(), nil, neigh.dest:string(), nil)
+ _add(what, neigh.mac:string(), nil, neigh.dest:string(), nil)
end
end)
if fs.access("/etc/ethers") then
for e in io.lines("/etc/ethers") do
- mac, ip = e:match("^([a-f0-9]%S+) (%S+)")
- if mac and ip then
- _add(what, mac:upper(), ip, nil, nil)
+ mac, name = e:match("^([a-fA-F0-9:-]+)%s+(%S+)")
+ mac = luci.ip.checkmac(mac)
+ if mac and name then
+ if luci.ip.checkip4(name) then
+ _add(what, mac, name, nil, nil)
+ else
+ _add(what, mac, nil, nil, name)
+ end
end
end
end
@@ -158,8 +163,9 @@ local function _nethints(what, callback)
if s.leasefile and fs.access(s.leasefile) then
for e in io.lines(s.leasefile) do
mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)")
+ mac = luci.ip.checkmac(mac)
if mac and ip then
- _add(what, mac:upper(), ip, nil, name ~= "*" and name)
+ _add(what, mac, ip, nil, name ~= "*" and name)
end
end
end
@@ -169,7 +175,10 @@ local function _nethints(what, callback)
cur:foreach("dhcp", "host",
function(s)
for mac in luci.util.imatch(s.mac) do
- _add(what, mac:upper(), s.ip, nil, s.name)
+ mac = luci.ip.checkmac(mac)
+ if mac then
+ _add(what, mac, s.ip, nil, s.name)
+ end
end
end)
diff --git a/modules/luci-base/luasrc/tools/status.lua b/modules/luci-base/luasrc/tools/status.lua
index 95ff46df1..501211181 100644
--- a/modules/luci-base/luasrc/tools/status.lua
+++ b/modules/luci-base/luasrc/tools/status.lua
@@ -4,6 +4,7 @@
module("luci.tools.status", package.seeall)
local uci = require "luci.model.uci".cursor()
+local ipc = require "luci.ip"
local function dhcp_leases_common(family)
local rv = { }
@@ -31,7 +32,7 @@ local function dhcp_leases_common(family)
if family == 4 and not ip:match(":") then
rv[#rv+1] = {
expires = (expire ~= 0) and os.difftime(expire, os.time()),
- macaddr = mac,
+ macaddr = ipc.checkmac(mac) or "00:00:00:00:00:00",
ipaddr = ip,
hostname = (name ~= "*") and name
}
@@ -74,19 +75,9 @@ local function dhcp_leases_common(family)
hostname = (name ~= "-") and name
}
elseif ip and iaid == "ipv4" and family == 4 then
- local mac, mac1, mac2, mac3, mac4, mac5, mac6
- if duid and type(duid) == "string" then
- mac1, mac2, mac3, mac4, mac5, mac6 = duid:match("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$")
- end
- if not (mac1 and mac2 and mac3 and mac4 and mac5 and mac6) then
- mac = "FF:FF:FF:FF:FF:FF"
- else
- mac = mac1..":"..mac2..":"..mac3..":"..mac4..":"..mac5..":"..mac6
- end
rv[#rv+1] = {
expires = (expire >= 0) and os.difftime(expire, os.time()),
- macaddr = duid,
- macaddr = mac:lower(),
+ macaddr = ipc.checkmac(duid:gsub("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$", "%1:%2:%3:%4:%5:%6")) or "00:00:00:00:00:00",
ipaddr = ip,
hostname = (name ~= "-") and name
}
diff --git a/modules/luci-base/luasrc/util.luadoc b/modules/luci-base/luasrc/util.luadoc
index 805eeb7f8..949aeb21c 100644
--- a/modules/luci-base/luasrc/util.luadoc
+++ b/modules/luci-base/luasrc/util.luadoc
@@ -109,13 +109,13 @@ Remove leading and trailing whitespace from given string value.
]]
---[[
-Count the occurences of given substring in given string.
+Count the occurrences of given substring in given string.
@class function
@name cmatch
@param str String to search in
@param pattern String containing pattern to find
-@return Number of found occurences
+@return Number of found occurrences
]]
---[[
diff --git a/modules/luci-base/luasrc/view/cbi/browser.htm b/modules/luci-base/luasrc/view/cbi/browser.htm
index a18120141..2abc975e8 100644
--- a/modules/luci-base/luasrc/view/cbi/browser.htm
+++ b/modules/luci-base/luasrc/view/cbi/browser.htm
@@ -2,6 +2,7 @@
<%+cbi/valueheader%>
<input class="cbi-input-text" type="text"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
<script type="text/javascript">
+cbi_init()
cbi_browser_init('<%=cbid%>', '<%=resource%>', '<%=url('admin/filebrowser')%>'<%=self.default_path and ", '"..self.default_path.."'"%>);
</script>
<%+cbi/valuefooter%>
diff --git a/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm b/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm
index 5cb31511f..b4260707e 100644
--- a/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm
+++ b/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm
@@ -24,70 +24,72 @@
end
-%>
-<ul style="margin:0; list-style-type:none; text-align:left">
- <% if self.allowlocal then %>
- <li style="padding:0.5em">
- <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_empty") .. attr("name", cbid) .. attr("value", "") .. ifattr(checked[""], "checked", "checked")%> /> &#160;
- <label<%=attr("for", cbid .. "_empty")%>></label>
- <label<%=attr("for", cbid .. "_empty")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
- <strong><%:Device%></strong>
- <% if self.allowany and self.allowlocal then %>(<%:input%>)<% end %>
- </label>
- </li>
- <% end %>
- <% if self.allowany then %>
- <li style="padding:0.5em">
- <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_any") .. attr("name", cbid) .. attr("value", "*") .. ifattr(checked["*"], "checked", "checked")%> /> &#160;
- <label<%=attr("for", cbid .. "_any")%>></label>
- <label<%=attr("for", cbid .. "_any")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
- <strong><%:Any zone%></strong>
- <% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %>
- </label>
- </li>
- <% end %>
- <%
- for _, zone in utl.spairs(zones, function(a,b) return (zones[a]:name() < zones[b]:name()) end) do
- if zone:name() ~= self.exclude then
- selected = selected or (value == zone:name())
- %>
- <li style="padding:0.5em">
- <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "." .. zone:name()) .. attr("name", cbid) .. attr("value", zone:name()) .. ifattr(checked[zone:name()], "checked", "checked")%> /> &#160;
- <label<%=attr("for", cbid .. "." .. zone:name())%>></label>
- <label<%=attr("for", cbid .. "." .. zone:name())%> style="background-color:<%=zone:get_color()%>" class="zonebadge">
- <strong><%=zone:name()%>:</strong>
- <%
- local zempty = true
- for _, net in ipairs(zone:get_networks()) do
- net = nwm:get_network(net)
- if net then
- zempty = false
- %>
- <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>:
+<span>
+ <ul style="margin:0; list-style-type:none; text-align:left">
+ <% if self.allowlocal then %>
+ <li style="padding:0.5em">
+ <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_empty") .. attr("name", cbid) .. attr("value", "") .. ifattr(checked[""], "checked", "checked")%> /> &#160;
+ <label<%=attr("for", cbid .. "_empty")%>></label>
+ <label<%=attr("for", cbid .. "_empty")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
+ <strong><%:Device%></strong>
+ <% if self.allowany and self.allowlocal then %>(<%:input%>)<% end %>
+ </label>
+ </li>
+ <% end %>
+ <% if self.allowany then %>
+ <li style="padding:0.5em">
+ <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_any") .. attr("name", cbid) .. attr("value", "*") .. ifattr(checked["*"], "checked", "checked")%> /> &#160;
+ <label<%=attr("for", cbid .. "_any")%>></label>
+ <label<%=attr("for", cbid .. "_any")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
+ <strong><%:Any zone%></strong>
+ <% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %>
+ </label>
+ </li>
+ <% end %>
+ <%
+ for _, zone in utl.spairs(zones, function(a,b) return (zones[a]:name() < zones[b]:name()) end) do
+ if zone:name() ~= self.exclude then
+ selected = selected or (value == zone:name())
+ %>
+ <li style="padding:0.5em">
+ <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "." .. zone:name()) .. attr("name", cbid) .. attr("value", zone:name()) .. ifattr(checked[zone:name()], "checked", "checked")%> /> &#160;
+ <label<%=attr("for", cbid .. "." .. zone:name())%>></label>
+ <label<%=attr("for", cbid .. "." .. zone:name())%> style="background-color:<%=zone:get_color()%>" class="zonebadge">
+ <strong><%=zone:name()%>:</strong>
<%
- local nempty = true
- for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do
- nempty = false
- %>
- <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
- <% end %>
- <% if nempty then %><em><%:(empty)%></em><% end %>
- </span>
- <% end end %>
- <% if zempty then %><em><%:(empty)%></em><% end %>
- </label>
- </li>
- <% end end %>
+ local zempty = true
+ for _, net in ipairs(zone:get_networks()) do
+ net = nwm:get_network(net)
+ if net then
+ zempty = false
+ %>
+ <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>:
+ <%
+ local nempty = true
+ for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do
+ nempty = false
+ %>
+ <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
+ <% end %>
+ <% if nempty then %><em><%:(empty)%></em><% end %>
+ </span>
+ <% end end %>
+ <% if zempty then %><em><%:(empty)%></em><% end %>
+ </label>
+ </li>
+ <% end end %>
- <% if self.widget ~= "checkbox" and not self.nocreate then %>
- <li style="padding:0.5em">
- <input class="cbi-input-radio" data-update="click change" type="radio"<%=attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not selected, "checked", "checked")%> /> &#160;
- <label<%=attr("for", cbid .. "_new")%>></label>
- <div onclick="document.getElementById('<%=cbid%>_new').checked=true" class="zonebadge" style="background-color:<%=fwm.zone.get_color()%>">
- <em><%:unspecified -or- create:%>&#160;</em>
- <input type="text"<%=attr("name", cbid .. ".newzone") .. ifattr(not selected, "value", luci.http.formvalue(cbid .. ".newzone") or self.default)%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" />
- </div>
- </li>
- <% end %>
-</ul>
+ <% if self.widget ~= "checkbox" and not self.nocreate then %>
+ <li style="padding:0.5em">
+ <input class="cbi-input-radio" data-update="click change" type="radio"<%=attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not selected, "checked", "checked")%> /> &#160;
+ <label<%=attr("for", cbid .. "_new")%>></label>
+ <div onclick="document.getElementById('<%=cbid%>_new').checked=true" class="zonebadge" style="background-color:<%=fwm.zone.get_color()%>">
+ <em><%:unspecified -or- create:%>&#160;</em>
+ <input type="text"<%=attr("name", cbid .. ".newzone") .. ifattr(not selected, "value", luci.http.formvalue(cbid .. ".newzone") or self.default)%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" />
+ </div>
+ </li>
+ <% end %>
+ </ul>
+</span>
<%+cbi/valuefooter%>
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
index 2cb2108b9..33f6a6703 100644
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
+++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
@@ -258,7 +258,6 @@ function iface_status(ifaces)
type = device:type(),
ifname = device:name(),
macaddr = device:mac(),
- macaddr = device:mac(),
is_up = device:is_up(),
rx_bytes = device:rx_bytes(),
tx_bytes = device:tx_bytes(),
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
index 2acda0b73..66d9942a1 100644
--- 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
@@ -2,6 +2,7 @@
-- 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"
@@ -311,10 +312,10 @@ end
hostid = s:option(Value, "hostid", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Suffix (hex)"))
-ipc.neighbors({ family = 4 }, function(n)
- if n.mac and n.dest then
- ip:value(n.dest:string())
- mac:value(n.mac, "%s (%s)" %{ n.mac, n.dest:string() })
+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)
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
index fafacf35c..46945af58 100644
--- 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
@@ -3,6 +3,7 @@
-- 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"))
@@ -19,9 +20,11 @@ ip = s:option(Value, "ip", translate("IP address"))
ip.datatype = "ipaddr"
ip.rmempty = true
-ipc.neighbors({ }, function(n)
- if n.mac and n.dest and not n.dest:is6linklocal() then
- ip:value(n.dest:string(), "%s (%s)" %{ n.dest:string(), n.mac })
+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)
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
index 4fc71cefa..8e7a3b066 100644
--- 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
@@ -16,6 +16,7 @@ local has_firewall = fs.access("/etc/config/firewall")
m = Map("network", translate("Interfaces") .. " - " .. arg[1]:upper(), translate("On this page you can configure the network interfaces. You can bridge several interfaces by ticking the \"bridge interfaces\" field and enter the names of several network interfaces separated by spaces. You can also use <abbr title=\"Virtual Local Area Network\">VLAN</abbr> notation <samp>INTERFACE.VLANNR</samp> (<abbr title=\"for example\">e.g.</abbr>: <samp>eth0.1</samp>)."))
m.redirect = luci.dispatcher.build_url("admin", "network", "network")
m:chain("wireless")
+m:chain("luci")
if has_firewall then
m:chain("firewall")
@@ -27,18 +28,52 @@ fw.init(m.uci)
local net = nw:get_network(arg[1])
+local function set_ifstate(name, option, value)
+ local found = false
+
+ m.uci:foreach("luci", "ifstate", function (s)
+ if s.interface == name then
+ m.uci:set("luci", s[".name"], option, value)
+ found = true
+ return false
+ end
+ end)
+
+ if not found then
+ local sid = m.uci:add("luci", "ifstate")
+ m.uci:set("luci", sid, "interface", name)
+ m.uci:set("luci", sid, option, value)
+ end
+
+ m.uci:save("luci")
+end
+
+local function get_ifstate(name, option)
+ local val
+
+ m.uci:foreach("luci", "ifstate", function (s)
+ if s.interface == name then
+ val = m.uci:get("luci", s[".name"], option)
+ return false
+ end
+ end)
+
+ return val
+end
+
local function backup_ifnames(is_bridge)
- if not net:is_floating() and not m:get(net:name(), "_orig_ifname") then
+ 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
- ifns[#ifns+1] = ifn:name()
+ local wif = ifn:get_wifinet()
+ ifns[#ifns+1] = wif and wif:id() or ifn:name()
end
if #ifns > 0 then
- m:set(net:name(), "_orig_ifname", table.concat(ifns, " "))
- m:set(net:name(), "_orig_bridge", tostring(net:is_bridge()))
+ set_ifstate(net:name(), "ifname", table.concat(ifns, " "))
+ set_ifstate(net:name(), "bridge", tostring(net:is_bridge()))
end
end
end
@@ -84,10 +119,10 @@ if m:formvalue("cbid.network.%s._switch" % net:name()) then
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 = (m:get(net:name(), "_orig_bridge") == "true")
+ local br = (get_ifstate(net:name(), "bridge") == "true")
local ifn
local ifns = { }
- for ifn in ut.imatch(m:get(net:name(), "_orig_ifname")) do
+ 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)
@@ -114,9 +149,7 @@ if m:formvalue("cbid.network.%s._switch" % net:name()) then
for k, v in pairs(m:get(net:name())) do
if k:sub(1,1) ~= "." and
k ~= "type" and
- k ~= "ifname" and
- k ~= "_orig_ifname" and
- k ~= "_orig_bridge"
+ k ~= "ifname"
then
m:del(net:name(), k)
end
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
index 5f2c07493..f474c7156 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
@@ -53,7 +53,7 @@
<tr class="cbi-section-table-row cbi-rowstyle-<%=(style and 1 or 2)%>">
<td class="cbi-value-field"><%=v.dest%></td>
<td class="cbi-value-field"><%=v.mac%></td>
- <td class="cbi-value-field"><%=v.dev%></td>
+ <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></td>
</tr>
<%
style = not style
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_system/flashops.htm b/modules/luci-mod-admin-full/luasrc/view/admin_system/flashops.htm
index 3e3f65d91..b32ef7826 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_system/flashops.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_system/flashops.htm
@@ -54,6 +54,9 @@
</div>
</form>
</div>
+ <% if reset_avail then %>
+ <div class="alert-message warning"><%:Custom files (certificates, scripts) may remain on the system. To prevent this, perform a factory-reset first.%></div>
+ <% end %>
</fieldset>
<br />
diff --git a/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua b/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
index 9a1c1fea4..bcc26cd44 100644
--- a/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
+++ b/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
@@ -3,7 +3,7 @@
-- Licensed to the public under the Apache License 2.0.
local uci = require "luci.model.uci".cursor()
-local ipc = require "luci.ip"
+local sys = require "luci.sys"
local wa = require "luci.tools.webadmin"
local fs = require "nixio.fs"
@@ -87,12 +87,11 @@ name = s2:option(Value, "name", translate("Hostname"))
mac = s2:option(Value, "mac", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
ip = s2:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
-ipc.neighbors({ family = 4 }, function(n)
- if n.mac and n.dest then
- ip:value(n.dest:string())
- mac:value(n.mac, "%s (%s)" %{ n.mac, n.dest:string() })
+sys.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)
return m
-