luci-app-olsr: migrate to js

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js fix XSS vulnerability

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix minor bugs

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix plugins bugs

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix interfaces bugs

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix interface & snr bugs

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix hostname

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix typo

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix missing files, use rpc for hostnames, remove luci-compat

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js

luci-app-olsr: migrate to js fix menu order

Signed-off-by: Ayushman Tripathi <ayushmantripathi7724@gmail.com>

luci-app-olsr: migrate to js
This commit is contained in:
Ayushman Tripathi 2023-06-26 01:23:48 +05:30
parent fd5440a7be
commit ebd09332b4
48 changed files with 4619 additions and 3344 deletions

View file

@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=OLSR configuration and status module
LUCI_DEPENDS:=+luci-compat +olsrd +olsrd-mod-jsoninfo +luci-lib-json
LUCI_DEPENDS:=+olsrd
include ../../luci.mk

View file

@ -0,0 +1,34 @@
function css(selector, property, value) {
for (var i = 0; i < document.styleSheets.length; i++) {
try {
document.styleSheets[i].insertRule(selector + ' {' + property + ':' + value + '}', document.styleSheets[i].cssRules.length);
} catch (err) {
try {
document.styleSheets[i].addRule(selector, property + ':' + value);
} catch (err) {}
} //IE
}
}
window.onload = function () {
var buttons = '<input type="button" name="show-proto-4" id="show-proto-4" class="cbi-button cbi-button-apply" style="margin-right: 5px" value="<%:Hide IPv4%>">';
buttons += '<input type="button" name="show-proto-6" id="show-proto-6" class="cbi-button cbi-button-apply" value="<%:Hide IPv6%>">';
document.getElementById('togglebuttons').innerHTML = buttons;
var visible = true;
document.getElementById('show-proto-4').onclick = function () {
visible = !visible;
document.getElementById('show-proto-4').value = visible ? '<%:Hide IPv4%>' : '<%:Show IPv4%>';
document.getElementById('show-proto-4').className = visible ? 'cbi-button cbi-button-apply' : 'cbi-button cbi-button-reset';
css('.proto-4', 'display', visible ? 'table-row' : 'none');
};
var visible6 = true;
document.getElementById('show-proto-6').onclick = function () {
visible6 = !visible6;
document.getElementById('show-proto-6').value = visible6 ? '<%:Hide IPv6%>' : '<%:Show IPv6%>';
document.getElementById('show-proto-6').className = visible6 ? 'cbi-button cbi-button-apply' : 'cbi-button cbi-button-reset';
css('.proto-6', 'display', visible6 ? 'table-row' : 'none');
};
};

View file

@ -0,0 +1,559 @@
'use strict';
'require view';
'require form';
'require fs';
'require uci';
'require ui';
'require rpc';
return view.extend({
callHasIpIp: rpc.declare({
object: 'olsrinfo',
method: 'hasipip',
}),
load: function () {
return Promise.all([uci.load('olsrd').then(() => {
var hasDefaults = false;
uci.sections('olsrd', 'InterfaceDefaults', function (s) {
hasDefaults = true;
return false;
});
if (!hasDefaults) {
uci.add('olsrd', 'InterfaceDefaults');
}
})]);
},
render: function () {
var m, s, o;
var has_ipip;
m = new form.Map(
'olsrd',
_('OLSR Daemon'),
_(
'The OLSR daemon is an implementation of the Optimized Link State Routing protocol. ' +
'As such it allows mesh routing for any network equipment. ' +
'It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. ' +
'Visit <a href="http://www.olsr.org">olsrd.org</a> for help and documentation.'
)
);
s = m.section(form.TypedSection, 'olsrd', _('General settings'));
s.anonymous = true;
s.tab('general', _('General Settings'));
s.tab('lquality', _('Link Quality Settings'));
this.callHasIpIp()
.then(function (res) {
var output = res.result;
has_ipip = output.trim().length > 0;
})
.catch(function (err) {
console.error(err);
})
.finally(function () {
s.tab('smartgw', _('SmartGW'), !has_ipip && _('Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it.'));
var sgw = s.taboption('smartgw', form.Flag, 'SmartGateway', _('Enable'), _('Enable SmartGateway. If it is disabled, then ' + 'all other SmartGateway parameters are ignored. Default is "no".'));
sgw.default = 'no';
sgw.enabled = 'yes';
sgw.disabled = 'no';
sgw.rmempty = true;
sgw.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, 'SmartGateway') || 'no';
};
var sgwnat = s.taboption('smartgw', form.Flag, 'SmartGatewayAllowNAT', _('Allow gateways with NAT'), _('Allow the selection of an outgoing IPv4 gateway with NAT'));
sgwnat.depends('SmartGateway', 'yes');
sgwnat.default = 'yes';
sgwnat.enabled = 'yes';
sgwnat.disabled = 'no';
sgwnat.optional = true;
sgwnat.rmempty = true;
var sgwuplink = s.taboption(
'smartgw',
form.ListValue,
'SmartGatewayUplink',
_('Announce uplink'),
_('Which kind of uplink is exported to the other mesh nodes. ' + 'An uplink is detected by looking for a local HNA of 0.0.0.0/0, ::ffff:0:0/96 or 2000::/3. Default setting is "both".')
);
sgwuplink.value('none');
sgwuplink.value('ipv4');
sgwuplink.value('ipv6');
sgwuplink.value('both');
sgwuplink.depends('SmartGateway', 'yes');
sgwuplink.default = 'both';
sgwuplink.optional = true;
sgwuplink.rmempty = true;
var sgwulnat = s.taboption('smartgw', form.Flag, 'SmartGatewayUplinkNAT', _('Uplink uses NAT'), _('If this Node uses NAT for connections to the internet. ' + 'Default is "yes".'));
sgwulnat.depends('SmartGatewayUplink', 'ipv4');
sgwulnat.depends('SmartGatewayUplink', 'both');
sgwulnat.default = 'yes';
sgwulnat.enabled = 'yes';
sgwulnat.disabled = 'no';
sgwnat.optional = true;
sgwnat.rmempty = true;
var sgwspeed = s.taboption('smartgw', form.Value, 'SmartGatewaySpeed', _('Speed of the uplink'), _('Specifies the speed of ' + 'the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is "128 1024".'));
sgwspeed.depends('SmartGatewayUplink', 'ipv4');
sgwspeed.depends('SmartGatewayUplink', 'ipv6');
sgwspeed.depends('SmartGatewayUplink', 'both');
sgwspeed.optional = true;
sgwspeed.rmempty = true;
var sgwprefix = s.taboption(
'smartgw',
form.Value,
'SmartGatewayPrefix',
_('IPv6-Prefix of the uplink'),
_(
'This can be used ' +
"to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " +
'use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. ' +
'Default is "::/0" (no prefix).'
)
);
sgwprefix.depends('SmartGatewayUplink', 'ipv6');
sgwprefix.depends('SmartGatewayUplink', 'both');
sgwprefix.optional = true;
sgwprefix.rmempty = true;
});
s.tab('advanced', _('Advanced Settings'));
var ipv = s.taboption('general', form.ListValue, 'IpVersion', _('Internet protocol'), _('IP-version to use. If 6and4 is selected then one olsrd instance is started for each protocol.'));
ipv.value('4', 'IPv4');
ipv.value('6and4', '6and4');
var poll = s.taboption('advanced', form.Value, 'Pollrate', _('Pollrate'), _('Polling rate for OLSR sockets in seconds. Default is 0.05.'));
poll.optional = true;
poll.datatype = 'ufloat';
poll.placeholder = '0.05';
var nicc = s.taboption('advanced', form.Value, 'NicChgsPollInt', _('Nic changes poll interval'), _('Interval to poll network interfaces for configuration changes (in seconds). Default is "2.5".'));
nicc.optional = true;
nicc.datatype = 'ufloat';
nicc.placeholder = '2.5';
var tos = s.taboption('advanced', form.Value, 'TosValue', _('TOS value'), _('Type of service value for the IP header of control traffic. Default is "16".'));
tos.optional = true;
tos.datatype = 'uinteger';
tos.placeholder = '16';
var fib = s.taboption(
'general',
form.ListValue,
'FIBMetric',
_('FIB metric'),
_(
'FIBMetric controls the metric value of the host-routes OLSRd sets. ' +
'"flat" means that the metric value is always 2. This is the preferred value ' +
'because it helps the Linux kernel routing to clean up older routes. ' +
'"correct" uses the hopcount as the metric value. ' +
'"approx" uses the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. ' +
'Default is "flat".'
)
);
fib.value('flat');
fib.value('correct');
fib.value('approx');
var lql = s.taboption(
'lquality',
form.ListValue,
'LinkQualityLevel',
_('LQ level'),
_('Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />' + '<b>0</b> = do not use link quality<br />' + '<b>2</b> = use link quality for MPR selection and routing<br />' + 'Default is "2"')
);
lql.value('2');
lql.value('0');
var lqage = s.taboption(
'lquality',
form.Value,
'LinkQualityAging',
_('LQ aging'),
_('Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values ' + 'mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)')
);
lqage.optional = true;
lqage.depends('LinkQualityLevel', '2');
var lqa = s.taboption(
'lquality',
form.ListValue,
'LinkQualityAlgorithm',
_('LQ algorithm'),
_(
'Link quality algorithm (only for lq level 2).<br />' +
'<b>etx_float</b>: floating point ETX with exponential aging<br />' +
'<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />' +
'<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />' +
'<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />' +
'Defaults to "etx_ff"'
)
);
lqa.optional = true;
lqa.value('etx_ff');
lqa.value('etx_fpm');
lqa.value('etx_float');
lqa.value('etx_ffeth');
lqa.depends('LinkQualityLevel', '2');
lqa.optional = true;
var lqfish = s.taboption('lquality', form.Flag, 'LinkQualityFishEye', _('LQ fisheye'), _('Fisheye mechanism for TCs (checked means on). Default is "on"'));
lqfish.default = '1';
lqfish.optional = true;
var hyst = s.taboption(
'lquality',
form.Flag,
'UseHysteresis',
_('Use hysteresis'),
_('Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing ' + 'but delays neighbor registration. Defaults is "yes"')
);
hyst.default = 'yes';
hyst.enabled = 'yes';
hyst.disabled = 'no';
hyst.depends('LinkQualityLevel', '0');
hyst.optional = true;
hyst.rmempty = true;
var port = s.taboption('general', form.Value, 'OlsrPort', _('Port'), _('The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535.'));
port.optional = true;
port.default = '698';
port.rmempty = true;
var mainip = s.taboption(
'general',
form.Value,
'MainIp',
_('Main IP'),
_('Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. ' + 'Default is 0.0.0.0, which triggers usage of the IP of the first interface.')
);
mainip.optional = true;
mainip.rmempty = true;
mainip.datatype = 'ipaddr';
mainip.placeholder = '0.0.0.0';
var willingness = s.taboption('advanced', form.ListValue, 'Willingness', _('Willingness'), _('The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is "3".'));
for (let i = 0; i < 8; i++) {
willingness.value(i);
}
willingness.optional = true;
willingness.default = '3';
var natthr = s.taboption(
'advanced',
form.Value,
'NatThreshold',
_('NAT threshold'),
_(
'If the route to the current gateway is to be changed, the ETX value of this gateway is ' +
'multiplied with this value before it is compared to the new one. ' +
'The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />' +
'<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />' +
'Defaults to "1.0".'
)
);
for (let i = 1; i >= 0.1; i -= 0.1) {
natthr.value(i);
}
natthr.depends('LinkQualityAlgorithm', 'etx_ff');
natthr.depends('LinkQualityAlgorithm', 'etx_float');
natthr.depends('LinkQualityAlgorithm', 'etx_fpm');
natthr.default = '1.0';
natthr.optional = true;
natthr.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'NatThreshold', n );
}
};
var i = m.section(form.TypedSection, 'InterfaceDefaults', _('Interfaces Defaults'));
i.anonymous = true;
i.addremove = false;
i.tab('general', _('General Settings'));
i.tab('addrs', _('IP Addresses'));
i.tab('timing', _('Timing and Validity'));
var mode = i.taboption('general', form.ListValue, 'Mode', _('Mode'), _('Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. ' + 'Valid modes are "mesh" and "ether". Default is "mesh".'));
mode.value('mesh');
mode.value('ether');
mode.optional = true;
mode.rmempty = true;
var weight = i.taboption(
'general',
form.Value,
'Weight',
_('Weight'),
_(
'When multiple links exist between hosts the weight of interface is used to determine the link to use. ' +
'Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, ' +
'but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />' +
'<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. ' +
'For any other value of LinkQualityLevel, the interface ETX value is used instead.'
)
);
weight.optional = true;
weight.datatype = 'uinteger';
weight.placeholder = '0';
var lqmult = i.taboption(
'general',
form.DynamicList,
'LinkQualityMult',
_('LinkQuality Multiplicator'),
_(
'Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. ' +
'It is only used when LQ-Level is greater than 0. Examples:<br />' +
'reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />' +
'reduce LQ to all nodes on this interface by 20%: default 0.8'
)
);
lqmult.optional = true;
lqmult.rmempty = true;
lqmult.cast = 'table';
lqmult.placeholder = 'default 1.0';
lqmult.validate = function (section_id) {
for (var i = 0; i < lqmult.formvalue(section_id).length; i++) {
var v = lqmult.formvalue(section_id)[i];
if (v !== '') {
var val = v.split(' ');
var host = val[0];
var mult = val[1];
if (!host || !mult) {
return [null, "LQMult requires two values (IP address or 'default' and multiplicator) separated by space."];
}
if (!/^(\d{1,3}\.){3}\d{1,3}$|^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/.test(host) && host !== 'default') {
return [null, "Can only be a valid IPv4 or IPv6 address or 'default'"];
}
if (isNaN(mult) || mult > 1 || mult < 0.01) {
return [null, 'Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.'];
}
if (!/^[0-1]\.\d+$/.test(mult)) {
return [null, 'Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.'];
}
}
}
return true;
};
var ip4b = i.taboption(
'addrs',
form.Value,
'Ip4Broadcast',
_('IPv4 broadcast'),
_('IPv4 broadcast address for outgoing OLSR packets. One useful example would be 255.255.255.255. ' + 'Default is "0.0.0.0", which triggers the usage of the interface broadcast IP.')
);
ip4b.optional = true;
ip4b.datatype = 'ip4addr';
ip4b.placeholder = '0.0.0.0';
var ip6m = i.taboption('addrs', form.Value, 'IPv6Multicast', _('IPv6 multicast'), _('IPv6 multicast address. Default is "FF02::6D", the manet-router linklocal multicast.'));
ip6m.optional = true;
ip6m.datatype = 'ip6addr';
ip6m.placeholder = 'FF02::6D';
var ip4s = i.taboption('addrs', form.Value, 'IPv4Src', _('IPv4 source'), _('IPv4 src address for outgoing OLSR packages. Default is "0.0.0.0", which triggers usage of the interface IP.'));
ip4s.optional = true;
ip4s.datatype = 'ip4addr';
ip4s.placeholder = '0.0.0.0';
var ip6s = i.taboption(
'addrs',
form.Value,
'IPv6Src',
_('IPv6 source'),
_('IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. ' + 'Default is "0::/0", which triggers the usage of a not-linklocal interface IP.')
);
ip6s.optional = true;
ip6s.datatype = 'ip6addr';
ip6s.placeholder = '0::/0';
var hi = i.taboption('timing', form.Value, 'HelloInterval', _('Hello interval'));
hi.optional = true;
hi.datatype = 'ufloat';
hi.placeholder = '5.0';
hi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HelloInterval', n);
}
};
var hv = i.taboption('timing', form.Value, 'HelloValidityTime', _('Hello validity time'));
hv.optional = true;
hv.datatype = 'ufloat';
hv.placeholder = '40.0';
hv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HelloValidityTime', n);
}
};
var ti = i.taboption('timing', form.Value, 'TcInterval', _('TC interval'));
ti.optional = true;
ti.datatype = 'ufloat';
ti.placeholder = '2.0';
ti.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'TcInterval', n);
}
};
var tv = i.taboption('timing', form.Value, 'TcValidityTime', _('TC validity time'));
tv.optional = true;
tv.datatype = 'ufloat';
tv.placeholder = '256.0';
tv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'TcValidityTime', n);
}
};
var mi = i.taboption('timing', form.Value, 'MidInterval', _('MID interval'));
mi.optional = true;
mi.datatype = 'ufloat';
mi.placeholder = '18.0';
mi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'MidInterval', n);
}
};
var mv = i.taboption('timing', form.Value, 'MidValidityTime', _('MID validity time'));
mv.optional = true;
mv.datatype = 'ufloat';
mv.placeholder = '324.0';
mv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'MidValidityTime', n);
}
};
var ai = i.taboption('timing', form.Value, 'HnaInterval', _('HNA interval'));
ai.optional = true;
ai.datatype = 'ufloat';
ai.placeholder = '18.0';
ai.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HnaInterval', n);
}
};
var av = i.taboption('timing', form.Value, 'HnaValidityTime', _('HNA validity time'));
av.optional = true;
av.datatype = 'ufloat';
av.placeholder = '108.0';
av.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HnaValidityTime', n);
}
};
var ifs = m.section(form.TableSection, 'Interface', _('Interfaces'));
ifs.addremove = true;
ifs.anonymous = true;
ifs.extedit = function (eve) {
var editButton = eve.target;
var sid;
var row = editButton.closest('.cbi-section-table-row');
if (row) {
sid = row.getAttribute('data-sid');
console.log(sid);
}
window.location.href = `olsrd/iface/${sid}`;
};
ifs.template = 'cbi/tblsection';
ifs.handleAdd = function (ev) {
var sid = uci.add('olsrd', 'Interface');
uci
.save()
.then(function () {
return uci.changes();
})
.then(function (res) {
console.log(res);
var sid = null;
if (res.olsrd && Array.isArray(res.olsrd)) {
res.olsrd.forEach(function (item) {
if (item.length >= 3 && item[0] === 'add' && item[2] === 'Interface') {
sid = item[1];
}
});
}
if (sid) {
console.log(sid);
}
window.location.href = `olsrd/iface/${sid}`;
});
};
var ign = ifs.option(form.Flag, 'ignore', _('Enable'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
ign.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, 'ignore') || '0';
};
var network = ifs.option(form.DummyValue, 'interface', _('Network'));
network.template = 'cbi/network_netinfo';
var mode = ifs.option(form.DummyValue, 'Mode', _('Mode'));
mode.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, 'Mode') || uci.get_first('olsrd', 'InterfaceDefaults', 'Mode');
};
var hello = ifs.option(form.DummyValue, '_hello', _('Hello'));
hello.cfgvalue = function (section_id) {
var i = uci.get('olsrd', section_id, 'HelloInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'HelloInterval');
var v = uci.get('olsrd', section_id, 'HelloValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'HelloValidityTime');
return `${i}s / ${v}s`;
};
var tc = ifs.option(form.DummyValue, '_tc', _('TC'));
tc.cfgvalue = function (section_id) {
var i = uci.get('olsrd', section_id, 'TcInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'TcInterval');
var v = uci.get('olsrd', section_id, 'TcValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'TcValidityTime');
return `${i}s / ${v}s`;
};
var mid = ifs.option(form.DummyValue, '_mid', _('MID'));
mid.cfgvalue = function (section_id) {
var i = uci.get('olsrd', section_id, 'MidInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'MidInterval');
var v = uci.get('olsrd', section_id, 'MidValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'MidValidityTime');
return `${i}s / ${v}s`;
};
var hna = ifs.option(form.DummyValue, '_hna', _('HNA'));
hna.cfgvalue = function (section_id) {
var i = uci.get('olsrd', section_id, 'HnaInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'HnaInterval');
var v = uci.get('olsrd', section_id, 'HnaValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'HnaValidityTime');
return `${i}s / ${v}s`;
};
return m.render();
},
});

View file

@ -0,0 +1,535 @@
'use strict';
'require view';
'require form';
'require fs';
'require uci';
'require ui';
'require rpc';
return view.extend({
callHasIpIp: rpc.declare({
object: 'olsrinfo',
method: 'hasipip',
}),
load: function () {
return Promise.all([uci.load('olsrd6').then(() => {
var hasDefaults = false;
uci.sections('olsrd6', 'InterfaceDefaults', function (s) {
hasDefaults = true;
return false;
});
if (!hasDefaults) {
uci.add('olsrd6', 'InterfaceDefaults');
}
})]);
},
render: function () {
var m, s, o;
var has_ipip;
m = new form.Map(
'olsrd6',
_('OLSR Daemon'),
_(
'The OLSR daemon is an implementation of the Optimized Link State Routing protocol. ' +
'As such it allows mesh routing for any network equipment. ' +
'It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. ' +
'Visit <a href="http://www.olsr.org">olsrd.org</a> for help and documentation.'
)
);
s = m.section(form.TypedSection, 'olsrd6', _('General settings'));
s.anonymous = true;
s.tab('general', _('General Settings'));
s.tab('lquality', _('Link Quality Settings'));
this.callHasIpIp()
.then(function (res) {
var output = res.result;
has_ipip = output.trim().length > 0;
})
.catch(function (err) {
console.error(err);
})
.finally(function () {
s.tab('smartgw', _('SmartGW'), !has_ipip && _('Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it.'));
var sgw = s.taboption('smartgw', form.Flag, 'SmartGateway', _('Enable'), _('Enable SmartGateway. If it is disabled, then ' + 'all other SmartGateway parameters are ignored. Default is "no".'));
sgw.default = 'no';
sgw.enabled = 'yes';
sgw.disabled = 'no';
sgw.rmempty = true;
sgw.cfgvalue = function (section_id) {
return uci.get('olsrd6', section_id, 'SmartGateway') || 'no';
};
var sgwnat = s.taboption('smartgw', form.Flag, 'SmartGatewayAllowNAT', _('Allow gateways with NAT'), _('Allow the selection of an outgoing IPv4 gateway with NAT'));
sgwnat.depends('SmartGateway', 'yes');
sgwnat.default = 'yes';
sgwnat.enabled = 'yes';
sgwnat.disabled = 'no';
sgwnat.optional = true;
sgwnat.rmempty = true;
var sgwuplink = s.taboption(
'smartgw',
form.ListValue,
'SmartGatewayUplink',
_('Announce uplink'),
_('Which kind of uplink is exported to the other mesh nodes. ' + 'An uplink is detected by looking for a local HNA6 ::ffff:0:0/96 or 2000::/3. Default setting is "both".')
);
sgwuplink.value('none');
sgwuplink.value('ipv4');
sgwuplink.value('ipv6');
sgwuplink.value('both');
sgwuplink.depends('SmartGateway', 'yes');
sgwuplink.default = 'both';
sgwuplink.optional = true;
sgwuplink.rmempty = true;
var sgwulnat = s.taboption('smartgw', form.Flag, 'SmartGatewayUplinkNAT', _('Uplink uses NAT'), _('If this Node uses NAT for connections to the internet. ' + 'Default is "yes".'));
sgwulnat.depends('SmartGatewayUplink', 'ipv4');
sgwulnat.depends('SmartGatewayUplink', 'both');
sgwulnat.default = 'yes';
sgwulnat.enabled = 'yes';
sgwulnat.disabled = 'no';
sgwnat.optional = true;
sgwnat.rmempty = true;
var sgwspeed = s.taboption('smartgw', form.Value, 'SmartGatewaySpeed', _('Speed of the uplink'), _('Specifies the speed of ' + 'the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is "128 1024".'));
sgwspeed.depends('SmartGatewayUplink', 'ipv4');
sgwspeed.depends('SmartGatewayUplink', 'ipv6');
sgwspeed.depends('SmartGatewayUplink', 'both');
sgwspeed.optional = true;
sgwspeed.rmempty = true;
var sgwprefix = s.taboption(
'smartgw',
form.Value,
'SmartGatewayPrefix',
_('IPv6-Prefix of the uplink'),
_(
'This can be used ' +
"to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " +
'use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. ' +
'Default is "::/0" (no prefix).'
)
);
sgwprefix.depends('SmartGatewayUplink', 'ipv6');
sgwprefix.depends('SmartGatewayUplink', 'both');
sgwprefix.optional = true;
sgwprefix.rmempty = true;
});
s.tab('advanced', _('Advanced Settings'));
var poll = s.taboption('advanced', form.Value, 'Pollrate', _('Pollrate'), _('Polling rate for OLSR sockets in seconds. Default is 0.05.'));
poll.optional = true;
poll.datatype = 'ufloat';
poll.placeholder = '0.05';
var nicc = s.taboption('advanced', form.Value, 'NicChgsPollInt', _('Nic changes poll interval'), _('Interval to poll network interfaces for configuration changes (in seconds). Default is "2.5".'));
nicc.optional = true;
nicc.datatype = 'ufloat';
nicc.placeholder = '2.5';
var tos = s.taboption('advanced', form.Value, 'TosValue', _('TOS value'), _('Type of service value for the IP header of control traffic. Default is "16".'));
tos.optional = true;
tos.datatype = 'uinteger';
tos.placeholder = '16';
var fib = s.taboption(
'general',
form.ListValue,
'FIBMetric',
_('FIB metric'),
_(
'FIBMetric controls the metric value of the host-routes OLSRd sets. ' +
'"flat" means that the metric value is always 2. This is the preferred value ' +
'because it helps the Linux kernel routing to clean up older routes. ' +
'"correct" uses the hopcount as the metric value. ' +
'"approx" uses the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. ' +
'Default is "flat".'
)
);
fib.value('flat');
fib.value('correct');
fib.value('approx');
var lql = s.taboption(
'lquality',
form.ListValue,
'LinkQualityLevel',
_('LQ level'),
_('Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />' + '<b>0</b> = do not use link quality<br />' + '<b>2</b> = use link quality for MPR selection and routing<br />' + 'Default is "2"')
);
lql.value('2');
lql.value('0');
var lqage = s.taboption(
'lquality',
form.Value,
'LinkQualityAging',
_('LQ aging'),
_('Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values ' + 'mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)')
);
lqage.optional = true;
lqage.depends('LinkQualityLevel', '2');
var lqa = s.taboption(
'lquality',
form.ListValue,
'LinkQualityAlgorithm',
_('LQ algorithm'),
_(
'Link quality algorithm (only for lq level 2).<br />' +
'<b>etx_float</b>: floating point ETX with exponential aging<br />' +
'<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />' +
'<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />' +
'<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />' +
'Defaults to "etx_ff"'
)
);
lqa.optional = true;
lqa.value('etx_ff');
lqa.value('etx_fpm');
lqa.value('etx_float');
lqa.value('etx_ffeth');
lqa.depends('LinkQualityLevel', '2');
lqa.optional = true;
var lqfish = s.taboption('lquality', form.Flag, 'LinkQualityFishEye', _('LQ fisheye'), _('Fisheye mechanism for TCs (checked means on). Default is "on"'));
lqfish.default = '1';
lqfish.optional = true;
var hyst = s.taboption(
'lquality',
form.Flag,
'UseHysteresis',
_('Use hysteresis'),
_('Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing ' + 'but delays neighbor registration. Defaults is "yes"')
);
hyst.default = 'yes';
hyst.enabled = 'yes';
hyst.disabled = 'no';
hyst.depends('LinkQualityLevel', '0');
hyst.optional = true;
hyst.rmempty = true;
var port = s.taboption('general', form.Value, 'OlsrPort', _('Port'), _('The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535.'));
port.optional = true;
port.default = '698';
port.rmempty = true;
var mainip = s.taboption(
'general',
form.Value,
'MainIp',
_('Main IP'),
_('Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. ' + 'Default is ::, which triggers usage of the IP of the first interface.')
);
mainip.optional = true;
mainip.rmempty = true;
mainip.datatype = 'ipaddr';
mainip.placeholder = '::';
var willingness = s.taboption('advanced', form.ListValue, 'Willingness', _('Willingness'), _('The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is "3".'));
for (let i = 0; i < 8; i++) {
willingness.value(i);
}
willingness.optional = true;
willingness.default = '3';
var natthr = s.taboption(
'advanced',
form.Value,
'NatThreshold',
_('NAT threshold'),
_(
'If the route to the current gateway is to be changed, the ETX value of this gateway is ' +
'multiplied with this value before it is compared to the new one. ' +
'The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />' +
'<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />' +
'Defaults to "1.0".'
)
);
for (let i = 1; i >= 0.1; i -= 0.1) {
natthr.value(i);
}
natthr.depends('LinkQualityAlgorithm', 'etx_ff');
natthr.depends('LinkQualityAlgorithm', 'etx_float');
natthr.depends('LinkQualityAlgorithm', 'etx_fpm');
natthr.default = '1.0';
natthr.optional = true;
natthr.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'NatThreshold', n);
}
};
var i = m.section(form.TypedSection, 'InterfaceDefaults', _('Interfaces Defaults'));
i.anonymous = true;
i.addremove = false;
i.tab('general', _('General Settings'));
i.tab('addrs', _('IP Addresses'));
i.tab('timing', _('Timing and Validity'));
var mode = i.taboption('general', form.ListValue, 'Mode', _('Mode'), _('Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. ' + 'Valid modes are "mesh" and "ether". Default is "mesh".'));
mode.value('mesh');
mode.value('ether');
mode.optional = true;
mode.rmempty = true;
var weight = i.taboption(
'general',
form.Value,
'Weight',
_('Weight'),
_(
'When multiple links exist between hosts the weight of interface is used to determine the link to use. ' +
'Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, ' +
'but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />' +
'<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. ' +
'For any other value of LinkQualityLevel, the interface ETX value is used instead.'
)
);
weight.optional = true;
weight.datatype = 'uinteger';
weight.placeholder = '0';
var lqmult = i.taboption(
'general',
form.DynamicList,
'LinkQualityMult',
_('LinkQuality Multiplicator'),
_(
'Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. ' +
'It is only used when LQ-Level is greater than 0. Examples:<br />' +
'reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />' +
'reduce LQ to all nodes on this interface by 20%: default 0.8'
)
);
lqmult.optional = true;
lqmult.rmempty = true;
lqmult.cast = 'table';
lqmult.placeholder = 'default 1.0';
lqmult.validate = function (section_id) {
for (var i = 0; i < lqmult.formvalue(section_id).length; i++) {
var v = lqmult.formvalue(section_id)[i];
if (v !== '') {
var val = v.split(' ');
var host = val[0];
var mult = val[1];
if (!host || !mult) {
return [null, "LQMult requires two values (IP address or 'default' and multiplicator) separated by space."];
}
if (!/^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/.test(host) && host !== 'default') {
return [null, "Can only be a valid IPv6 address or 'default'"];
}
if (isNaN(mult) || mult > 1 || mult < 0.01) {
return [null, 'Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.'];
}
if (!/^[0-1]\.\d+$/.test(mult)) {
return [null, 'Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.'];
}
}
}
return true;
};
var ip6m = i.taboption('addrs', form.Value, 'IPv6Multicast', _('IPv6 multicast'), _('IPv6 multicast address. Default is "FF02::6D", the manet-router linklocal multicast.'));
ip6m.optional = true;
ip6m.datatype = 'ip6addr';
ip6m.placeholder = 'FF02::6D';
var ip6s = i.taboption(
'addrs',
form.Value,
'IPv6Src',
_('IPv6 source'),
_('IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. ' + 'Default is "0::/0", which triggers the usage of a not-linklocal interface IP.')
);
ip6s.optional = true;
ip6s.datatype = 'ip6addr';
ip6s.placeholder = '0::/0';
var hi = i.taboption('timing', form.Value, 'HelloInterval', _('Hello interval'));
hi.optional = true;
hi.datatype = 'ufloat';
hi.placeholder = '5.0';
hi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HelloInterval', n);
}
};
var hv = i.taboption('timing', form.Value, 'HelloValidityTime', _('Hello validity time'));
hv.optional = true;
hv.datatype = 'ufloat';
hv.placeholder = '40.0';
hv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HelloValidityTime', n);
}
};
var ti = i.taboption('timing', form.Value, 'TcInterval', _('TC interval'));
ti.optional = true;
ti.datatype = 'ufloat';
ti.placeholder = '2.0';
ti.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'TcInterval', n);
}
};
var tv = i.taboption('timing', form.Value, 'TcValidityTime', _('TC validity time'));
tv.optional = true;
tv.datatype = 'ufloat';
tv.placeholder = '256.0';
tv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'TcValidityTime', n);
}
};
var mi = i.taboption('timing', form.Value, 'MidInterval', _('MID interval'));
mi.optional = true;
mi.datatype = 'ufloat';
mi.placeholder = '18.0';
mi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'MidInterval', n);
}
};
var mv = i.taboption('timing', form.Value, 'MidValidityTime', _('MID validity time'));
mv.optional = true;
mv.datatype = 'ufloat';
mv.placeholder = '324.0';
mv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'MidValidityTime', n);
}
};
var ai = i.taboption('timing', form.Value, 'HnaInterval', _('HNA interval'));
ai.optional = true;
ai.datatype = 'ufloat';
ai.placeholder = '18.0';
ai.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HnaInterval', n);
}
};
var av = i.taboption('timing', form.Value, 'HnaValidityTime', _('HNA validity time'));
av.optional = true;
av.datatype = 'ufloat';
av.placeholder = '108.0';
av.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HnaValidityTime', n);
}
};
var ifs = m.section(form.TableSection, 'Interface', _('Interfaces'));
ifs.addremove = true;
ifs.anonymous = true;
ifs.extedit = function (eve) {
var editButton = eve.target;
var sid;
var row = editButton.closest('.cbi-section-table-row');
if (row) {
sid = row.getAttribute('data-sid');
console.log(sid);
}
window.location.href = `olsrd6/iface/${sid}`;
};
ifs.template = 'cbi/tblsection';
ifs.handleAdd = function (ev) {
var sid = uci.add('olsrd6', 'Interface');
uci
.save()
.then(function () {
return uci.changes();
})
.then(function (res) {
console.log(res);
var sid = null;
if (res.olsrd6 && Array.isArray(res.olsrd6)) {
res.olsrd6.forEach(function (item) {
if (item.length >= 3 && item[0] === 'add' && item[2] === 'Interface') {
sid = item[1];
}
});
}
if (sid) {
console.log(sid);
}
window.location.href = `olsrd6/iface/${sid}`;
});
};
var ign = ifs.option(form.Flag, 'ignore', _('Enable'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
ign.cfgvalue = function (section_id) {
return uci.get('olsrd6', section_id, 'ignore') || '0';
};
var network = ifs.option(form.DummyValue, 'interface', _('Network'));
network.template = 'cbi/network_netinfo';
var mode = ifs.option(form.DummyValue, 'Mode', _('Mode'));
mode.cfgvalue = function (section_id) {
return uci.get('olsrd6', section_id, 'Mode') || uci.get_first('olsrd6', 'InterfaceDefaults', 'Mode');
};
var hello = ifs.option(form.DummyValue, '_hello', _('Hello'));
hello.cfgvalue = function (section_id) {
var i = uci.get('olsrd6', section_id, 'HelloInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HelloInterval');
var v = uci.get('olsrd6', section_id, 'HelloValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HelloValidityTime');
return `${i}s / ${v}s`;
};
var tc = ifs.option(form.DummyValue, '_tc', _('TC'));
tc.cfgvalue = function (section_id) {
var i = uci.get('olsrd6', section_id, 'TcInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'TcInterval');
var v = uci.get('olsrd6', section_id, 'TcValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'TcValidityTime');
return `${i}s / ${v}s`;
};
var mid = ifs.option(form.DummyValue, '_mid', _('MID'));
mid.cfgvalue = function (section_id) {
var i = uci.get('olsrd6', section_id, 'MidInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'MidInterval');
var v = uci.get('olsrd6', section_id, 'MidValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'MidValidityTime');
return `${i}s / ${v}s`;
};
var hna = ifs.option(form.DummyValue, '_hna', _('HNA'));
hna.cfgvalue = function (section_id) {
var i = uci.get('olsrd6', section_id, 'HnaInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HnaInterval');
var v = uci.get('olsrd6', section_id, 'HnaValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HnaValidityTime');
return `${i}s / ${v}s`;
};
return m.render();
},
});

View file

@ -0,0 +1,30 @@
'use strict';
'require view';
'require form';
'require ui';
'require uci';
return view.extend({
load: function () {
return Promise.all([uci.load('luci_olsr')]);
},
render: function () {
var m, s, o;
m = new form.Map('luci_olsr', _('OLSR - Display Options'));
s = m.section(form.TypedSection, 'olsr');
s.anonymous = true;
var res = s.option(
form.Flag,
'resolve',
_('Resolve'),
_('Resolve hostnames on status pages. It is generally safe to allow this, but if you use public IPs and have unstable DNS-Setup then those pages will load really slow. In this case disable it here.')
);
res.default = '0';
res.optional = true;
return m.render();
},
});

View file

@ -0,0 +1,49 @@
'use strict';
'require view';
'require form';
'require uci';
'require ui';
return view.extend({
load: function () {
return Promise.all([uci.load('olsrd')]);
},
render: function () {
var ipv = uci.get_first('olsrd', 'olsrd', 'IpVersion') || '4';
var mh = new form.Map('olsrd', _('OLSR - HNA-Announcements'), _('Hosts in an OLSR routed network can announce connectivity ' + 'to external networks using HNA messages.'));
if (ipv === '6and4' || ipv === '4') {
var hna4 = mh.section(form.TypedSection, 'Hna4', _('Hna4'), _('Both values must use the dotted decimal notation.'));
hna4.addremove = true;
hna4.anonymous = true;
hna4.template = 'cbi/tblsection';
var net4 = hna4.option(form.Value, 'netaddr', _('Network address'));
net4.datatype = 'ip4addr';
net4.placeholder = '10.11.12.13';
net4.default = '10.11.12.13';
var msk4 = hna4.option(form.Value, 'netmask', _('Netmask'));
msk4.datatype = 'ip4addr';
msk4.placeholder = '255.255.255.255';
msk4.default = '255.255.255.255';
}
if (ipv === '6and4' || ipv === '6') {
var hna6 = mh.section(form.TypedSection, 'Hna6', _('Hna6'), _('IPv6 network must be given in full notation, ' + 'prefix must be in CIDR notation.'));
hna6.addremove = true;
hna6.anonymous = true;
hna6.template = 'cbi/tblsection';
var net6 = hna6.option(form.Value, 'netaddr', _('Network address'));
net6.datatype = 'ip6addr';
net6.placeholder = 'fec0:2200:106:0:0:0:0:0';
net6.default = 'fec0:2200:106:0:0:0:0:0';
var msk6 = hna6.option(form.Value, 'prefix', _('Prefix'));
msk6.datatype = 'range(0,128)';
msk6.placeholder = '128';
msk6.default = '128';
}
return mh.render();
},
});

View file

@ -0,0 +1,30 @@
'use strict';
'require view';
'require form';
'require uci';
'require ui';
return view.extend({
load: function () {
return Promise.all([uci.load('olsrd6')]);
},
render: function () {
var mh = new form.Map('olsrd6', _('OLSR - HNA6-Announcements'), _('Hosts in an OLSR routed network can announce connectivity ' + 'to external networks using HNA6 messages.'));
var hna6 = mh.section(form.TypedSection, 'Hna6', _('Hna6'), _('IPv6 network must be given in full notation, ' + 'prefix must be in CIDR notation.'));
hna6.addremove = true;
hna6.anonymous = true;
hna6.template = 'cbi/tblsection';
var net6 = hna6.option(form.Value, 'netaddr', _('Network address'));
net6.datatype = 'ip6addr';
net6.placeholder = 'fec0:2200:106:0:0:0:0:0';
net6.default = 'fec0:2200:106:0:0:0:0:0';
var msk6 = hna6.option(form.Value, 'prefix', _('Prefix'));
msk6.datatype = 'range(0,128)';
msk6.placeholder = '128';
msk6.default = '128';
return mh.render();
},
});

View file

@ -0,0 +1,239 @@
'use strict';
'require view';
'require form';
'require uci';
'require ui';
'require tools.widgets as widgets';
return view.extend({
load: function () {
return Promise.all([uci.load('olsrd')]);
},
render: function () {
var m = new form.Map(
'olsrd',
_('OLSR Daemon - Interface'),
_(
'The OLSR daemon is an implementation of the Optimized Link State Routing protocol. ' +
'As such it allows mesh routing for any network equipment. ' +
'It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. ' +
"Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."
)
);
var pathname = window.location.pathname;
var segments = pathname.split('/');
var sidIndex = segments.lastIndexOf('iface') + 1;
var sid = null;
if (sidIndex !== -1 && sidIndex < segments.length) {
sid = segments[sidIndex];
}
var i = m.section(form.NamedSection, sid, 'Interface', _('Interface'));
i.anonymous = true;
i.addremove = false;
i.tab('general', _('General Settings'));
i.tab('addrs', _('IP Addresses'));
i.tab('timing', _('Timing and Validity'));
var ign = i.taboption('general', form.Flag, 'ignore', _('Enable'), _('Enable this interface.'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
ign.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, 'ignore') || '0';
};
var network = i.taboption('general', widgets.NetworkSelect, 'interface', _('Network'), _('The interface OLSRd should serve.'));
network.optional = false;
var mode = i.taboption('general', form.ListValue, 'Mode', _('Mode'), _('Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. ' + 'Valid modes are "mesh" and "ether". Default is "mesh".'));
mode.value('mesh');
mode.value('ether');
mode.optional = true;
mode.rmempty = true;
var weight = i.taboption(
'general',
form.Value,
'Weight',
_('Weight'),
_(
'When multiple links exist between hosts the weight of interface is used to determine the link to use. ' +
'Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, ' +
'but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />' +
'<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. ' +
'For any other value of LinkQualityLevel, the interface ETX value is used instead.'
)
);
weight.optional = true;
weight.datatype = 'uinteger';
weight.placeholder = '0';
var lqmult = i.taboption(
'general',
form.DynamicList,
'LinkQualityMult',
_('LinkQuality Multiplicator'),
_(
'Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. ' +
'It is only used when LQ-Level is greater than 0. Examples:<br />' +
'reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />' +
'reduce LQ to all nodes on this interface by 20%: default 0.8'
)
);
lqmult.optional = true;
lqmult.rmempty = true;
lqmult.cast = 'table';
lqmult.placeholder = 'default 1.0';
lqmult.validate = function (section_id) {
for (var i = 0; i < lqmult.formvalue(section_id).length; i++) {
var v = lqmult.formvalue(section_id)[i];
if (v !== '') {
var val = v.split(' ');
var host = val[0];
var mult = val[1];
if (!host || !mult) {
return [null, "LQMult requires two values (IP address or 'default' and multiplicator) separated by space."];
}
if (!/^(\d{1,3}\.){3}\d{1,3}$|^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/.test(host) && host !== 'default') {
return [null, "Can only be a valid IPv4 or IPv6 address or 'default'"];
}
if (isNaN(mult) || mult > 1 || mult < 0.01) {
return [null, 'Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.'];
}
if (!/^[0-1]\.\d+$/.test(mult)) {
return [null, 'Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.'];
}
}
}
return true;
};
var ip4b = i.taboption(
'addrs',
form.Value,
'Ip4Broadcast',
_('IPv4 broadcast'),
_('IPv4 broadcast address for outgoing OLSR packets. One useful example would be 255.255.255.255. ' + 'Default is "0.0.0.0", which triggers the usage of the interface broadcast IP.')
);
ip4b.optional = true;
ip4b.datatype = 'ip4addr';
ip4b.placeholder = '0.0.0.0';
var ip6m = i.taboption('addrs', form.Value, 'IPv6Multicast', _('IPv6 multicast'), _('IPv6 multicast address. Default is "FF02::6D", the manet-router linklocal multicast.'));
ip6m.optional = true;
ip6m.datatype = 'ip6addr';
ip6m.placeholder = 'FF02::6D';
var ip4s = i.taboption('addrs', form.Value, 'IPv4Src', _('IPv4 source'), _('IPv4 src address for outgoing OLSR packages. Default is "0.0.0.0", which triggers usage of the interface IP.'));
ip4s.optional = true;
ip4s.datatype = 'ip4addr';
ip4s.placeholder = '0.0.0.0';
var ip6s = i.taboption(
'addrs',
form.Value,
'IPv6Src',
_('IPv6 source'),
_('IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. ' + 'Default is "0::/0", which triggers the usage of a not-linklocal interface IP.')
);
ip6s.optional = true;
ip6s.datatype = 'ip6addr';
ip6s.placeholder = '0::/0';
var hi = i.taboption('timing', form.Value, 'HelloInterval', _('Hello interval'));
hi.optional = true;
hi.datatype = 'ufloat';
hi.placeholder = '5.0';
hi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HelloInterval', n);
}
};
var hv = i.taboption('timing', form.Value, 'HelloValidityTime', _('Hello validity time'));
hv.optional = true;
hv.datatype = 'ufloat';
hv.placeholder = '40.0';
hv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HelloValidityTime', n);
}
};
var ti = i.taboption('timing', form.Value, 'TcInterval', _('TC interval'));
ti.optional = true;
ti.datatype = 'ufloat';
ti.placeholder = '2.0';
ti.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'TcInterval', n);
}
};
var tv = i.taboption('timing', form.Value, 'TcValidityTime', _('TC validity time'));
tv.optional = true;
tv.datatype = 'ufloat';
tv.placeholder = '256.0';
tv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'TcValidityTime', n);
}
};
var mi = i.taboption('timing', form.Value, 'MidInterval', _('MID interval'));
mi.optional = true;
mi.datatype = 'ufloat';
mi.placeholder = '18.0';
mi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'MidInterval', n);
}
};
var mv = i.taboption('timing', form.Value, 'MidValidityTime', _('MID validity time'));
mv.optional = true;
mv.datatype = 'ufloat';
mv.placeholder = '324.0';
mv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'MidValidityTime', n);
}
};
var ai = i.taboption('timing', form.Value, 'HnaInterval', _('HNA interval'));
ai.optional = true;
ai.datatype = 'ufloat';
ai.placeholder = '18.0';
ai.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HnaInterval', n);
}
};
var av = i.taboption('timing', form.Value, 'HnaValidityTime', _('HNA validity time'));
av.optional = true;
av.datatype = 'ufloat';
av.placeholder = '108.0';
av.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd', section_id, 'HnaValidityTime', n);
}
};
return m.render();
},
});

View file

@ -0,0 +1,223 @@
'use strict';
'require view';
'require form';
'require uci';
'require ui';
'require tools.widgets as widgets';
return view.extend({
load: function () {
return Promise.all([uci.load('olsrd6')]);
},
render: function () {
var m = new form.Map(
'olsrd6',
_('OLSR Daemon - Interface'),
_(
'The OLSR daemon is an implementation of the Optimized Link State Routing protocol. ' +
'As such it allows mesh routing for any network equipment. ' +
'It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. ' +
"Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."
)
);
var pathname = window.location.pathname;
var segments = pathname.split('/');
var sidIndex = segments.lastIndexOf('iface') + 1;
var sid = null;
if (sidIndex !== -1 && sidIndex < segments.length) {
sid = segments[sidIndex];
}
var i = m.section(form.NamedSection, sid, 'Interface', _('Interface'));
i.anonymous = true;
i.addremove = false;
i.tab('general', _('General Settings'));
i.tab('addrs', _('IP Addresses'));
i.tab('timing', _('Timing and Validity'));
var ign = i.taboption('general', form.Flag, 'ignore', _('Enable'), _('Enable this interface.'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
ign.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, 'ignore') || '0';
};
var network = i.taboption('general', widgets.NetworkSelect, 'interface', _('Network'), _('The interface OLSRd should serve.'));
network.optional = false;
var mode = i.taboption('general', form.ListValue, 'Mode', _('Mode'), _('Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. ' + 'Valid modes are "mesh" and "ether". Default is "mesh".'));
mode.value('mesh');
mode.value('ether');
mode.optional = true;
mode.rmempty = true;
var weight = i.taboption(
'general',
form.Value,
'Weight',
_('Weight'),
_(
'When multiple links exist between hosts the weight of interface is used to determine the link to use. ' +
'Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, ' +
'but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />' +
'<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. ' +
'For any other value of LinkQualityLevel, the interface ETX value is used instead.'
)
);
weight.optional = true;
weight.datatype = 'uinteger';
weight.placeholder = '0';
var lqmult = i.taboption(
'general',
form.DynamicList,
'LinkQualityMult',
_('LinkQuality Multiplicator'),
_(
'Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. ' +
'It is only used when LQ-Level is greater than 0. Examples:<br />' +
'reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />' +
'reduce LQ to all nodes on this interface by 20%: default 0.8'
)
);
lqmult.optional = true;
lqmult.rmempty = true;
lqmult.cast = 'table';
lqmult.placeholder = 'default 1.0';
lqmult.validate = function (section_id) {
for (var i = 0; i < lqmult.formvalue(section_id).length; i++) {
var v = lqmult.formvalue(section_id)[i];
if (v !== '') {
var val = v.split(' ');
var host = val[0];
var mult = val[1];
if (!host || !mult) {
return [null, "LQMult requires two values (IP address or 'default' and multiplicator) separated by space."];
}
if (!/^(\d{1,3}\.){3}\d{1,3}$|^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/.test(host) && host !== 'default') {
return [null, "Can only be a valid IPv4 or IPv6 address or 'default'"];
}
if (isNaN(mult) || mult > 1 || mult < 0.01) {
return [null, 'Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.'];
}
if (!/^[0-1]\.\d+$/.test(mult)) {
return [null, 'Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.'];
}
}
}
return true;
};
var ip6m = i.taboption('addrs', form.Value, 'IPv6Multicast', _('IPv6 multicast'), _('IPv6 multicast address. Default is "FF02::6D", the manet-router linklocal multicast.'));
ip6m.optional = true;
ip6m.datatype = 'ip6addr';
ip6m.placeholder = 'FF02::6D';
var ip6s = i.taboption(
'addrs',
form.Value,
'IPv6Src',
_('IPv6 source'),
_('IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. ' + 'Default is "0::/0", which triggers the usage of a not-linklocal interface IP.')
);
ip6s.optional = true;
ip6s.datatype = 'ip6addr';
ip6s.placeholder = '0::/0';
var hi = i.taboption('timing', form.Value, 'HelloInterval', _('Hello interval'));
hi.optional = true;
hi.datatype = 'ufloat';
hi.placeholder = '5.0';
hi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HelloInterval', n);
}
};
var hv = i.taboption('timing', form.Value, 'HelloValidityTime', _('Hello validity time'));
hv.optional = true;
hv.datatype = 'ufloat';
hv.placeholder = '40.0';
hv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HelloValidityTime', n);
}
};
var ti = i.taboption('timing', form.Value, 'TcInterval', _('TC interval'));
ti.optional = true;
ti.datatype = 'ufloat';
ti.placeholder = '2.0';
ti.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'TcInterval', n);
}
};
var tv = i.taboption('timing', form.Value, 'TcValidityTime', _('TC validity time'));
tv.optional = true;
tv.datatype = 'ufloat';
tv.placeholder = '256.0';
tv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'TcValidityTime', n);
}
};
var mi = i.taboption('timing', form.Value, 'MidInterval', _('MID interval'));
mi.optional = true;
mi.datatype = 'ufloat';
mi.placeholder = '18.0';
mi.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'MidInterval', n);
}
};
var mv = i.taboption('timing', form.Value, 'MidValidityTime', _('MID validity time'));
mv.optional = true;
mv.datatype = 'ufloat';
mv.placeholder = '324.0';
mv.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'MidValidityTime', n);
}
};
var ai = i.taboption('timing', form.Value, 'HnaInterval', _('HNA interval'));
ai.optional = true;
ai.datatype = 'ufloat';
ai.placeholder = '18.0';
ai.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HnaInterval', n);
}
};
var av = i.taboption('timing', form.Value, 'HnaValidityTime', _('HNA validity time'));
av.optional = true;
av.datatype = 'ufloat';
av.placeholder = '108.0';
av.write = function (section_id, value) {
let n = parseFloat(value).toFixed(1);
if (!isNaN(n)) {
uci.set('olsrd6', section_id, 'HnaValidityTime', n);
}
};
return m.render();
},
});

View file

@ -0,0 +1,292 @@
'use strict';
'require view';
'require form';
'require uci';
'require ui';
'require fs';
'require network';
'require validation';
return view.extend({
load: function () {
return Promise.all([
uci.load('olsrd').then(() => {
return fs.list('/usr/lib').then((files) => {
const sections = uci.sections('olsrd', 'LoadPlugin');
const libsArr = [];
sections.forEach((section) => {
const lib = section.library;
libsArr.push(lib);
});
files.forEach((v) => {
if (v.name.substr(0, 6) === 'olsrd_') {
var pluginname = v.name.match(/^(olsrd.*)\.so\..*/)[1];
if (!libsArr.includes(pluginname)) {
var sid = uci.add('olsrd', 'LoadPlugin');
uci.set('olsrd', sid, 'ignore', '1');
uci.set('olsrd', sid, 'library', pluginname);
}
}
});
});
}),
]);
},
render: function () {
var pathname = window.location.pathname;
var segments = pathname.split('/');
var sidIndex = segments.lastIndexOf('plugins') + 1;
var sid = null;
if (sidIndex !== -1 && sidIndex < segments.length) {
sid = segments[sidIndex];
}
if (sid) {
var mp = new form.Map('olsrd', _('OLSR - Plugins'));
var p = mp.section(form.NamedSection, sid, 'LoadPlugin', _('Plugin configuration'));
p.anonymous = true;
var plname = uci.get('olsrd', sid, 'library');
var ign = p.option(form.Flag, 'ignore', _('Enable'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
ign.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, 'ignore') || '0';
};
var lib = p.option(form.DummyValue, 'library', _('Library'));
lib.default = plname;
function Range(x, y) {
var t = [];
for (var i = x; i <= y; i++) {
t.push(i);
}
return t;
}
function Cidr2IpMask(val) {
function prefixToMask(prefix, isIPv6) {
return isIPv6 ? network.prefixToMask(prefix, true) : network.prefixToMask(prefix, false);
}
if (val) {
var newVal = val.map(cidr => {
var [ip, prefix] = cidr.split('/');
var networkip, mask;
if (validation.parseIPv6(ip)) {
networkip = ip;
mask = prefixToMask(parseInt(prefix), true);
} else if (validation.parseIPv4(ip)) {
networkip = ip;
mask = prefixToMask(parseInt(prefix), false);
}
return networkip && mask ? networkip + ' ' + mask : cidr;
});
}
return newVal;
}
function IpMask2Cidr(val) {
if (val) {
for (let i = 0; i < val.length; i++) {
var [ip, mask] = val[i].match(/([^ ]+)%s+([^ ]+)/) || [];
var cidr;
if (ip && mask) {
if (validation.parseIPv6(ip)) {
cidr = ip + '/' + mask;
} else if (validation.parseIPv4(ip)) {
var ipParts = ip.split('.');
var maskParts = mask.split('.');
var cidrParts = [];
for (let j = 0; j < 4; j++) {
var ipPart = parseInt(ipParts[j]);
var maskPart = parseInt(maskParts[j]);
var cidrPart = ipPart & maskPart;
cidrParts.push(cidrPart);
}
var cidrPrefix = network.maskToPrefix(maskParts.join('.'));
cidr = cidrParts.join('.') + '/' + cidrPrefix;
}
}
if (cidr) {
val[i] = cidr;
}
}
}
return val;
}
const knownPlParams = {
olsrd_bmf: [
[form.Value, 'BmfInterface', 'bmf0'],
[form.Value, 'BmfInterfaceIp', '10.10.10.234/24'],
[form.Flag, 'DoLocalBroadcast', 'no'],
[form.Flag, 'CapturePacketsOnOlsrInterfaces', 'yes'],
[form.ListValue, 'BmfMechanism', ['UnicastPromiscuous', 'Broadcast']],
[form.Value, 'BroadcastRetransmitCount', '2'],
[form.Value, 'FanOutLimit', '4'],
[form.DynamicList, 'NonOlsrIf', 'br-lan'],
],
olsrd_dyn_gw: [
[form.Value, 'Interval', '40'],
[form.DynamicList, 'Ping', '141.1.1.1'],
[form.DynamicList, 'HNA', '192.168.80.0/24', IpMask2Cidr, Cidr2IpMask],
],
olsrd_httpinfo: [
[form.Value, 'port', '80'],
[form.DynamicList, 'Host', '163.24.87.3'],
[form.DynamicList, 'Net', '0.0.0.0/0', Cidr2IpMask],
],
olsrd_nameservice: [
[form.DynamicList, 'name', 'my-name.mesh'],
[form.DynamicList, 'hosts', '1.2.3.4 name-for-other-interface.mesh'],
[form.Value, 'suffix', '.olsr'],
[form.Value, 'hosts_file', '/path/to/hosts_file'],
[form.Value, 'add_hosts', '/path/to/file'],
[form.Value, 'dns_server', '141.1.1.1'],
[form.Value, 'resolv_file', '/path/to/resolv.conf'],
[form.Value, 'interval', '120'],
[form.Value, 'timeout', '240'],
[form.Value, 'lat', '12.123'],
[form.Value, 'lon', '12.123'],
[form.Value, 'latlon_file', '/var/run/latlon.js'],
[form.Value, 'latlon_infile', '/var/run/gps.txt'],
[form.Value, 'sighup_pid_file', '/var/run/dnsmasq.pid'],
[form.Value, 'name_change_script', '/usr/local/bin/announce_new_hosts.sh'],
[form.DynamicList, 'service', 'http://me.olsr:80|tcp|my little homepage'],
[form.Value, 'services_file', '/var/run/services_olsr'],
[form.Value, 'services_change_script', '/usr/local/bin/announce_new_services.sh'],
[form.DynamicList, 'mac', 'xx:xx:xx:xx:xx:xx[,0-255]'],
[form.Value, 'macs_file', '/path/to/macs_file'],
[form.Value, 'macs_change_script', '/path/to/script'],
],
olsrd_quagga: [
[form.DynamicList, 'redistribute', ['system', 'kernel', 'connect', 'static', 'rip', 'ripng', 'ospf', 'ospf6', 'isis', 'bgp', 'hsls']],
[form.ListValue, 'ExportRoutes', ['only', 'both']],
[form.Flag, 'LocalPref', 'true'],
[form.Value, 'Distance', Range(0, 255)],
],
olsrd_secure: [[form.Value, 'Keyfile', '/etc/private-olsr.key']],
olsrd_txtinfo: [[form.Value, 'accept', '127.0.0.1']],
olsrd_jsoninfo: [
[form.Value, 'accept', '127.0.0.1'],
[form.Value, 'port', '9090'],
[form.Value, 'UUIDFile', '/etc/olsrd/olsrd.uuid'],
],
olsrd_watchdog: [
[form.Value, 'file', '/var/run/olsrd.watchdog'],
[form.Value, 'interval', '30'],
],
olsrd_mdns: [[form.DynamicList, 'NonOlsrIf', 'lan']],
olsrd_p2pd: [
[form.DynamicList, 'NonOlsrIf', 'lan'],
[form.Value, 'P2pdTtl', '10'],
],
olsrd_arprefresh: [],
olsrd_dot_draw: [],
olsrd_dyn_gw_plain: [],
olsrd_pgraph: [],
olsrd_tas: [],
};
if (knownPlParams[plname]) {
for (const option of knownPlParams[plname]) {
const [otype, name, defaultVal, uci2cbi, cbi2uci] = option;
let values;
if (Array.isArray(defaultVal)) {
values = defaultVal;
defaultVal = defaultVal[0];
}
if (otype === form.Flag) {
const bool = p.option(form.Flag, name, name);
if (defaultVal === 'yes' || defaultVal === 'no') {
bool.enabled = 'yes';
bool.disabled = 'no';
} else if (defaultVal === 'on' || defaultVal === 'off') {
bool.enabled = 'on';
bool.disabled = 'off';
} else if (defaultVal === '1' || defaultVal === '0') {
bool.enabled = '1';
bool.disabled = '0';
} else {
bool.enabled = 'true';
bool.disabled = 'false';
}
bool.optional = true;
bool.placeholder = defaultVal;
bool.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, name);
};
} else {
const field = p.option(otype, name, name);
if (values) {
for (const value of values) {
field.value(value);
}
}
field.cfgvalue = function (section_id) {
return uci.get('olsrd', section_id, name);
};
if (typeof uci2cbi === 'function') {
field.cfgvalue = function (section_id) {
return uci2cbi(uci.get('olsrd', section_id, name));
};
}
if (typeof cbi2uci === 'function') {
field.write = function (section_id, formvalue) {
var saveval=cbi2uci(formvalue);
uci.set('olsrd', section_id, name, saveval);
};
}
field.optional = true;
field.placeholder = defaultVal;
}
}
}
return mp.render();
} else {
var mpi = new form.Map('olsrd', _('OLSR - Plugins'));
var t = mpi.section(form.TableSection, 'LoadPlugin', _('Plugins'));
t.anonymous = true;
t.extedit = function (eve) {
var editButton = eve.target;
var sid;
var row = editButton.closest('.cbi-section-table-row');
if (row) {
sid = row.getAttribute('data-sid');
console.log(sid);
}
window.location.href = `plugins/${sid}`;
};
var ign = t.option(form.Flag, 'ignore', _('Enabled'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
function ign_cfgvalue(section_id) {
return uci.get(section_id, 'ignore') || '0';
}
t.option(form.DummyValue, 'library', _('Library'));
return mpi.render();
}
},
});

View file

@ -0,0 +1,290 @@
'use strict';
'require view';
'require form';
'require uci';
'require ui';
'require fs';
return view.extend({
load: function () {
return Promise.all([
uci.load('olsrd6').then(() => {
return fs.list('/usr/lib').then((files) => {
const sections = uci.sections('olsrd6', 'LoadPlugin');
const libsArr = [];
sections.forEach((section) => {
const lib = section.library;
libsArr.push(lib);
});
files.forEach((v) => {
if (v.name.substr(0, 6) === 'olsrd_') {
var pluginname = v.name.match(/^(olsrd_.*)\.so\..*/)[1];
if (!libsArr.includes(pluginname)) {
var sid = uci.add('olsrd6', 'LoadPlugin');
uci.set('olsrd6', sid, 'ignore', '1');
uci.set('olsrd6', sid, 'library', pluginname);
}
}
});
});
}),
]);
},
render: function () {
var pathname = window.location.pathname;
var segments = pathname.split('/');
var sidIndex = segments.lastIndexOf('plugins') + 1;
var sid = null;
if (sidIndex !== -1 && sidIndex < segments.length) {
sid = segments[sidIndex];
}
if (sid) {
var mp = new form.Map('olsrd6', _('OLSR - Plugins'));
var p = mp.section(form.NamedSection, sid, 'LoadPlugin', _('Plugin configuration'));
p.anonymous = true;
var plname = uci.get('olsrd6', sid, 'library');
var ign = p.option(form.Flag, 'ignore', _('Enable'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
ign.cfgvalue = function (section_id) {
return uci.get('olsrd6', section_id, 'ignore') || '0';
};
var lib = p.option(form.DummyValue, 'library', _('Library'));
lib.default = plname;
function Range(x, y) {
var t = [];
for (var i = x; i <= y; i++) {
t.push(i);
}
return t;
}
function Cidr2IpMask(val) {
function prefixToMask(prefix, isIPv6) {
return isIPv6 ? network.prefixToMask(prefix, true) : network.prefixToMask(prefix, false);
}
if (val) {
var newVal = val.map(cidr => {
var [ip, prefix] = cidr.split('/');
var networkip, mask;
if (validation.parseIPv6(ip)) {
networkip = ip;
mask = prefixToMask(parseInt(prefix), true);
} else if (validation.parseIPv4(ip)) {
networkip = ip;
mask = prefixToMask(parseInt(prefix), false);
}
return networkip && mask ? networkip + ' ' + mask : cidr;
});
}
return newVal;
}
function IpMask2Cidr(val) {
if (val) {
for (let i = 0; i < val.length; i++) {
var [ip, mask] = val[i].match(/([^ ]+)%s+([^ ]+)/) || [];
var cidr;
if (ip && mask) {
if (validation.parseIPv6(ip)) {
cidr = ip + '/' + mask;
} else if (validation.parseIPv4(ip)) {
var ipParts = ip.split('.');
var maskParts = mask.split('.');
var cidrParts = [];
for (let j = 0; j < 4; j++) {
var ipPart = parseInt(ipParts[j]);
var maskPart = parseInt(maskParts[j]);
var cidrPart = ipPart & maskPart;
cidrParts.push(cidrPart);
}
var cidrPrefix = network.maskToPrefix(maskParts.join('.'));
cidr = cidrParts.join('.') + '/' + cidrPrefix;
}
}
if (cidr) {
val[i] = cidr;
}
}
}
return val;
}
const knownPlParams = {
olsrd_bmf: [
[form.Value, 'BmfInterface', 'bmf0'],
[form.Value, 'BmfInterfaceIp', '10.10.10.234/24'],
[form.Flag, 'DoLocalBroadcast', 'no'],
[form.Flag, 'CapturePacketsOnOlsrInterfaces', 'yes'],
[form.ListValue, 'BmfMechanism', ['UnicastPromiscuous', 'Broadcast']],
[form.Value, 'BroadcastRetransmitCount', '2'],
[form.Value, 'FanOutLimit', '4'],
[form.DynamicList, 'NonOlsrIf', 'br-lan'],
],
olsrd_dyn_gw: [
[form.Value, 'Interval', '40'],
[form.DynamicList, 'Ping', '141.1.1.1'],
[form.DynamicList, 'HNA', '192.168.80.0/24', IpMask2Cidr, Cidr2IpMask],
],
olsrd_httpinfo: [
[form.Value, 'port', '80'],
[form.DynamicList, 'Host', '163.24.87.3'],
[form.DynamicList, 'Net', '0.0.0.0/0', Cidr2IpMask],
],
olsrd_nameservice: [
[form.DynamicList, 'name', 'my-name.mesh'],
[form.DynamicList, 'hosts', '1.2.3.4 name-for-other-interface.mesh'],
[form.Value, 'suffix', '.olsr'],
[form.Value, 'hosts_file', '/path/to/hosts_file'],
[form.Value, 'add_hosts', '/path/to/file'],
[form.Value, 'dns_server', '141.1.1.1'],
[form.Value, 'resolv_file', '/path/to/resolv.conf'],
[form.Value, 'interval', '120'],
[form.Value, 'timeout', '240'],
[form.Value, 'lat', '12.123'],
[form.Value, 'lon', '12.123'],
[form.Value, 'latlon_file', '/var/run/latlon.js.ipv6'],
[form.Value, 'latlon_infile', '/var/run/gps.txt'],
[form.Value, 'sighup_pid_file', '/var/run/dnsmasq.pid'],
[form.Value, 'name_change_script', '/usr/local/bin/announce_new_hosts.sh'],
[form.DynamicList, 'service', 'http://me.olsr:80|tcp|my little homepage'],
[form.Value, 'services_file', '/var/run/services_olsr'],
[form.Value, 'services_change_script', '/usr/local/bin/announce_new_services.sh'],
[form.DynamicList, 'mac', 'xx:xx:xx:xx:xx:xx[,0-255]'],
[form.Value, 'macs_file', '/path/to/macs_file'],
[form.Value, 'macs_change_script', '/path/to/script'],
],
olsrd_quagga: [
[form.DynamicList, 'redistribute', ['system', 'kernel', 'connect', 'static', 'rip', 'ripng', 'ospf', 'ospf6', 'isis', 'bgp', 'hsls']],
[form.ListValue, 'ExportRoutes', ['only', 'both']],
[form.Flag, 'LocalPref', 'true'],
[form.Value, 'Distance', Range(0, 255)],
],
olsrd_secure: [[form.Value, 'Keyfile', '/etc/private-olsr.key']],
olsrd_txtinfo: [[form.Value, 'accept', '::1/128']],
olsrd_jsoninfo: [
[form.Value, 'accept', '::1/128'],
[form.Value, 'port', '9090'],
[form.Value, 'UUIDFile', '/etc/olsrd/olsrd.uuid.ipv6'],
],
olsrd_watchdog: [
[form.Value, 'file', '/var/run/olsrd.watchdog.ipv6'],
[form.Value, 'interval', '30'],
],
olsrd_mdns: [[form.DynamicList, 'NonOlsrIf', 'lan']],
olsrd_p2pd: [
[form.DynamicList, 'NonOlsrIf', 'lan'],
[form.Value, 'P2pdTtl', '10'],
],
olsrd_arprefresh: [],
olsrd_dot_draw: [],
olsrd_dyn_gw_plain: [],
olsrd_pgraph: [],
olsrd_tas: [],
};
if (knownPlParams[plname]) {
for (const option of knownPlParams[plname]) {
const [otype, name, defaultVal, uci2cbi, cbi2uci] = option;
let values;
if (Array.isArray(defaultVal)) {
values = defaultVal;
defaultVal = defaultVal[0];
}
if (otype === form.Flag) {
const bool = p.option(form.Flag, name, name);
if (defaultVal === 'yes' || defaultVal === 'no') {
bool.enabled = 'yes';
bool.disabled = 'no';
} else if (defaultVal === 'on' || defaultVal === 'off') {
bool.enabled = 'on';
bool.disabled = 'off';
} else if (defaultVal === '1' || defaultVal === '0') {
bool.enabled = '1';
bool.disabled = '0';
} else {
bool.enabled = 'true';
bool.disabled = 'false';
}
bool.optional = true;
bool.placeholder = defaultVal;
bool.cfgvalue = function (section_id) {
return uci.get('olsrd6', section_id, name);
};
} else {
const field = p.option(otype, name, name);
if (values) {
for (const value of values) {
field.value(value);
}
}
field.cfgvalue = function (section_id) {
return uci.get('olsrd6', section_id, name);
};
if (typeof uci2cbi === 'function') {
field.cfgvalue = function (section_id) {
return uci2cbi(uci.get('olsrd6', section_id, name));
};
}
if (typeof cbi2uci === 'function') {
field.write = function (section_id, formvalue) {
var saveval=cbi2uci(formvalue);
uci.set('olsrd6', section_id, name, saveval);
};
}
field.optional = true;
field.placeholder = defaultVal;
}
}
}
return mp.render();
} else {
var mpi = new form.Map('olsrd6', _('OLSR - Plugins'));
var t = mpi.section(form.TableSection, 'LoadPlugin', _('Plugins'));
t.anonymous = true;
t.extedit = function (eve) {
var editButton = eve.target;
var sid;
var row = editButton.closest('.cbi-section-table-row');
if (row) {
sid = row.getAttribute('data-sid');
console.log(sid);
}
window.location.href = `plugins/${sid}`;
};
var ign = t.option(form.Flag, 'ignore', _('Enabled'));
ign.enabled = '0';
ign.disabled = '1';
ign.rmempty = false;
function ign_cfgvalue(section_id) {
return uci.get(section_id, 'ignore') || '0';
}
t.option(form.DummyValue, 'library', _('Library'));
return mpi.render();
}
},
});

View file

@ -0,0 +1,16 @@
'use strict';
'require view';
'require rpc';
'require ui';
return view.extend({
render: function () {
return E('div', {}, [
E('h2', { 'name': 'content' }, _('OLSR Daemon')),
E('p', { 'class': 'error' }, _('Unable to connect to the OLSR daemon!')),
E('p', {}, [_('Make sure that OLSRd is running, the "jsoninfo" plugin is loaded, configured on port 9090, and accepts connections from "127.0.0.1".')]),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -0,0 +1,271 @@
'use strict';
'require uci';
'require view';
'require poll';
'require network';
'require rpc';
'require ui';
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
callGetHosts: rpc.declare({
object: 'olsrinfo',
method: 'hosts',
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_hna: function () {
var self = this;
return new Promise(function (resolve, reject) {
self
.fetch_jsoninfo('hna')
.then(function ([data, has_v4, has_v6, error]) {
if (error) {
reject(error);
}
var resolveVal = uci.get('luci_olsr', 'general', 'resolve');
function compare(a, b) {
if (a.proto === b.proto) {
return a.genmask < b.genmask;
} else {
return a.proto < b.proto;
}
}
var modifiedData;
self
.callGetHosts()
.then(function (res) {
function matchHostnames(ip) {
var lines = res.hosts.split('\n');
for (var i = 0; i < lines.length; i++) {
var ipandhostname = lines[i].trim().split(/\s+/);
if (ipandhostname[0] === ip) {
return ipandhostname[1];
}
}
return null;
}
modifiedData = data.map(function (v) {
if (resolveVal === '1') {
var hostname = matchHostnames(v.gateway);
if (hostname) {
v.hostname = hostname;
}
}
if (v.validityTime) {
v.validityTime = parseInt((v.validityTime / 1000).toFixed(0));
}
return v;
});
modifiedData.sort(compare);
var result = { hna: modifiedData, has_v4: has_v4, has_v6: has_v6 };
resolve(result);
})
.catch(function (err) {
modifiedData = data;
console.error(err);
});
})
.catch(function (err) {
reject(err);
});
});
},
load: function () {
var self = this;
poll.add(function () {
self.render();
}, 5);
return Promise.all([uci.load('olsrd'), uci.load('luci_olsr')]);
},
render: function () {
var hna_res;
var has_v4;
var has_v6;
var self = this;
return this.action_hna()
.then(function (result) {
hna_res = result.hna;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var table = E('div', { 'class': 'table cbi-section-table', 'id': 'olsrd_hna' }, [
E('div', { 'class': 'tr cbi-section-table-titles' }, [
E('div', { 'class': 'th cbi-section-table-cell' }, _('Announced network')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('OLSR gateway')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Validity Time')),
]),
]);
var i = 1;
var rv = [];
for (var k = 0; k < hna_res.length; k++) {
var entry = hna_res[k];
rv.push({
proto: entry.proto,
destination: entry.destination,
genmask: entry.genmask,
gateway: entry.gateway,
hostname: entry.hostname,
validityTime: entry.validityTime,
});
}
var info = rv;
var hnadiv = document.getElementById('olsrd_hna');
if (hnadiv) {
var s =
'<div class="tr cbi-section-table-titles">' +
'<div class="th cbi-section-table-cell">Announced network</div>' +
'<div class="th cbi-section-table-cell">OLSR gateway</div>' +
'<div class="th cbi-section-table-cell">Validity Time</div>' +
'</div>';
for (var idx = 0; idx < info.length; idx++) {
var hna = info[idx];
var linkgw = '';
s += '<div class="tr cbi-section-table-row cbi-rowstyle-' + (1 + (idx % 2)) + ' proto-' + hna.proto + '">';
if (hna.proto === '6') {
linkgw = '<a href="http://[' + hna.gateway + ']/cgi-bin-status.html">' + hna.gateway + '</a>';
} else {
linkgw = '<a href="http://' + hna.gateway + '/cgi-bin-status.html">' + hna.gateway + '</a>';
}
var validity = hna.validityTime !== undefined ? hna.validityTime + 's' : '-';
var hostname = hna.hostname !== null ? ' / <a href="http://%q/cgi-bin-status.html">%h</a>'.format(hna.hostname, hna.hostname) : '';
s +=
'<div class="td cbi-section-table-cell left">' +
(hna.destination + '/' + hna.genmask) +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
(linkgw + hostname) +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
validity +
'</div>' +
'</div>';
}
hnadiv.innerHTML = s;
}
var i = 1;
for (var k = 0; k < hna_res.length; k++) {
var route = hna_res[k];
var tr = E('div', { 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + route.proto }, [
E('div', { 'class': 'td cbi-section-table-cell left' }, route.destination + '/' + route.genmask),
E('div', { 'class': 'td cbi-section-table-cell left' }, [
route.proto === '6' ? E('a', { 'href': 'http://[' + route.gateway + ']/cgi-bin-status.html' }, route.gateway) : E('a', { 'href': 'http://' + route.gateway + '/cgi-bin-status.html' }, route.gateway),
route.hostname ? E('span', {}, [' / ', E('a', { 'href': 'http://%q/cgi-bin-status.html'.format(route.hostname) }, '%h'.format(route.hostname))]) : '',
]),
E('div', { 'class': 'td cbi-section-table-cell left' }, route.validityTime ? route.validityTime + 's' : '-'),
]);
table.appendChild(tr);
i = (i % 2) + 1;
}
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of currently active OLSR host net announcements')), table]);
var h2 = E('h2', { 'name': 'content' }, _('Active host net announcements'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', { 'type': 'text/javascript', 'src': L.resource('common/common_js.js') });
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrCommonJs]);
return result;
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -0,0 +1,186 @@
'use strict';
'require uci';
'require view';
'require rpc';
'require ui';
'require network';
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_interfaces: async function () {
try {
const [data, has_v4, has_v6, error] = await this.fetch_jsoninfo('interfaces');
if (error) {
throw error;
}
function compare(a, b) {
return a.proto < b.proto;
}
const modifiedData = await Promise.all(
data.map(async function (v) {
const interfac = await network.getStatusByAddress(v.olsrInterface.ipAddress);
if (interfac) {
v.interface = interfac;
}
return v;
})
);
modifiedData.sort(compare);
const result = {
iface: modifiedData,
has_v4: has_v4,
has_v6: has_v6,
};
return result;
} catch (err) {
throw err;
}
},
load: function () {
return Promise.all([uci.load('olsrd'), uci.load('luci_olsr')]);
},
render: function () {
var iface_res;
var has_v4;
var has_v6;
var self = this;
return this.action_interfaces()
.then(function (result) {
iface_res = result.iface;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var table = E('div', { 'class': 'table cbi-section-table' }, [
E('div', { 'class': 'tr' }, [
E('div', { 'class': 'th cbi-section-table-cell' }, _('Interface')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Device')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('State')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('MTU')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('WLAN')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Source address')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Netmask')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Broadcast address')),
]),
]);
var i = 1;
for (var k = 0; k < iface_res.length; k++) {
var iface = iface_res[k];
var tr = E('div', { 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + iface.proto }, [
E('div', { 'class': 'td cbi-section-table-cell left' }, iface?.interface?.interface ?? '?'),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.name),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.olsrInterface.up ? _('up') : _('down')),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.olsrInterface.mtu),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.olsrInterface.wireless ? _('yes') : _('no')),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.olsrInterface.ipAddress),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.olsrInterface.ipv4Address !== '0.0.0.0' ? iface.olsrInterface.ipv4Netmask : ''),
E('div', { 'class': 'td cbi-section-table-cell left' }, iface.olsrInterface.ipv4Address !== '0.0.0.0' ? iface.olsrInterface.ipv4Broadcast : iface.olsrInterface.ipv6Multicast),
]);
table.appendChild(tr);
i = (i % 2) + 1;
}
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of interfaces where OLSR is running')), table]);
var h2 = E('h2', { 'name': 'content' }, _('Interfaces'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', { 'type': 'text/javascript', 'src': L.resource('common/common_js.js') });
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrCommonJs]);
return result;
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -0,0 +1,171 @@
'use strict';
'require uci';
'require view';
'require rpc';
'require ui';
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_mid: function () {
var self = this;
return new Promise(function (resolve, reject) {
self
.fetch_jsoninfo('mid')
.then(function ([data, has_v4, has_v6, error]) {
if (error) {
reject(error);
}
function compare(a, b) {
if (a.proto === b.proto) {
return a.main.ipAddress < b.main.ipAddress;
} else {
return a.proto < b.proto;
}
}
data.sort(compare);
var result = { mids: data, has_v4: has_v4, has_v6: has_v6 };
resolve(result);
})
.catch(function (err) {
reject(err);
});
});
},
render: function () {
var mids_res;
var has_v4;
var has_v6;
return this.action_mid()
.then(function (result) {
mids_res = result.mids;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var table = E('div', { 'class': 'table cbi-section-table' }, [
E('div', { 'class': 'tr cbi-section-table-titles' }, [E('div', { 'class': 'th cbi-section-table-cell' }, _('OLSR node')), E('div', { class: 'th cbi-section-table-cell' }, _('Secondary OLSR interfaces'))]),
]);
var i = 1;
for (var k = 0; k < mids_res.length; k++) {
var mid = mids_res[k];
var aliases = '';
for (var j = 0; j < mid.aliases.length; j++) {
var v = mid.aliases[j];
var sep = aliases === '' ? '' : ', ';
aliases = v.ipAddress + sep + aliases;
}
var host = mid.main.ipAddress;
if (mid.proto === '6') {
host = '[' + mid.main.ipAddress + ']';
}
var tr = E('div', { 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + mid.proto }, [
E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://' + host + '/cgi-bin-status.html' }, mid.main.ipAddress)]),
E('div', { 'class': 'td cbi-section-table-cell left' }, aliases),
]);
table.appendChild(tr);
i = (i % 2) + 1;
}
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of known multiple interface announcements')), table]);
var h2 = E('h2', { 'name': 'content' }, _('Active MID announcements'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', { 'type': 'text/javascript', 'src': L.resource('common/common_js.js') });
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrCommonJs]);
return result;
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -0,0 +1,579 @@
'use strict';
'require uci';
'require view';
'require poll';
'require rpc';
'require ui';
'require network';
function etx_color(etx) {
let color = '#bb3333';
if (etx === 0) {
color = '#bb3333';
} else if (etx < 2) {
color = '#00cc00';
} else if (etx < 4) {
color = '#ffcb05';
} else if (etx < 10) {
color = '#ff6600';
}
return color;
}
function snr_colors(snr) {
let color = '#bb3333';
if (snr === 0) {
color = '#bb3333';
} else if (snr > 30) {
color = '#00cc00';
} else if (snr > 20) {
color = '#ffcb05';
} else if (snr > 5) {
color = '#ff6600';
}
return color;
}
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
callGetHosts: rpc.declare({
object: 'olsrinfo',
method: 'hosts',
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_neigh: async function () {
try {
const [data, has_v4, has_v6, error] = await this.fetch_jsoninfo('links');
if (error) {
throw error;
}
function compare(a, b) {
if (a.proto === b.proto) {
return a.linkCost < b.linkCost;
} else {
return a.proto < b.proto;
}
}
var assoclist = [];
var resolveVal = uci.get('luci_olsr', 'general', 'resolve');
var devices;
var defaultgw;
devices = await network.getWifiDevices();
var rts = await network.getWANNetworks();
rts.forEach(function (rt) {
defaultgw = rt.getGatewayAddr() || '0.0.0.0';
});
var networkPromises = devices.map(async function (dev) {
var networks = await dev.getWifiNetworks();
var promiseArr = networks.map(async function (net) {
var radio = await net.getDevice();
var [ifname, devnetwork, device, list] = await Promise.all([net.getIfname(), net.getNetworkNames(), radio ? radio.getName() : null, net.getAssocList()]);
assoclist.push({
ifname: ifname,
network: devnetwork[0],
device: device,
list: list,
});
});
await Promise.all(promiseArr);
});
await Promise.all(networkPromises);
var res = '';
var self = this;
await (async function() {
try {
res = await self.callGetHosts();
}
catch (e) {
console.error(e);
}
})();
function matchHostnames(ip) {
var lines = res.hosts.split('\n');
for (var i = 0; i < lines.length; i++) {
var ipandhostname = lines[i].trim().split(/\s+/);
if (ipandhostname[0] === ip) {
return ipandhostname[1];
}
}
return null;
}
var modifiedData = await Promise.all(
data.map(async function (v) {
var snr = 0;
var signal = 0;
var noise = 0;
var mac = '';
var ip;
var neihgt = [];
if (resolveVal === '1') {
var hostname = matchHostnames(v.remoteIP);
if (hostname) {
v.hostname = hostname;
}
}
var hosthints = await network.getHostHints();
var interfac = await network.getStatusByAddress(v.localIP);
var lmac = await hosthints.getMACAddrByIPAddr(v.localIP);
var rmac = await hosthints.getMACAddrByIPAddr(v.remoteIP);
for (let i = 0; i < assoclist.length; i++) {
var val = assoclist[i];
if (val.network === interfac.interface && val.list) {
for (var assocmac in val.list) {
var assot = val.list[assocmac];
if (rmac == assot.mac) {
signal = parseInt(assot.signal);
noise = parseInt(assot.noise);
snr = noise * -1 - signal * -1;
}
}
}
}
if (interfac) {
v.interface = interfac;
}
v.snr = snr || null;
v.signal = signal || null;
v.noise = noise || null;
if (rmac) {
v.remoteMAC = rmac;
}
if (lmac) {
v.localMAC = lmac;
}
if (defaultgw === v.remoteIP) {
v.defaultgw = 1;
}
return v;
})
);
modifiedData.sort(compare);
var result = { links: modifiedData, has_v4: has_v4, has_v6: has_v6 };
return result;
} catch (err) {
console.error(err);
throw err;
}
},
load: function () {
var self = this;
poll.add(function () {
self.render();
}, 5);
return Promise.all([uci.load('olsrd'), uci.load('luci_olsr')]);
},
render: function () {
var neigh_res;
var has_v4;
var has_v6;
var self = this;
return this.action_neigh()
.then(function (result) {
neigh_res = result.links;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var table = E('div', { 'class': 'table cbi-section-table', 'id': 'olsr_neigh_table' }, [
E('div', { 'class': 'tr cbi-section-table-cell' }, [
E('div', { 'class': 'th cbi-section-table-cell' }, _('Neighbour IP')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Hostname')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Interface')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Local interface IP')),
E('div', { 'class': 'th cbi-section-table-cell' }, 'LQ'),
E('div', { 'class': 'th cbi-section-table-cell' }, 'NLQ'),
E('div', { 'class': 'th cbi-section-table-cell' }, 'ETX'),
E('div', { 'class': 'th cbi-section-table-cell' }, 'SNR'),
]),
]);
var rv = [];
for (var k = 0; k < neigh_res.length; k++) {
var link = neigh_res[k];
link.linkCost = parseInt(link.linkCost) || 0;
if (link.linkCost === 4194304) {
link.linkCost = 0;
}
var color = etx_color(link.linkCost);
var snr_color = snr_colors(link.snr);
var defaultgw_color = '';
if (link.defaultgw === 1) {
defaultgw_color = '#ffff99';
}
rv.push({
rip: link.remoteIP,
hn: link.hostname,
lip: link.localIP,
ifn: link.interface,
lq: link.linkQuality.toFixed(3),
nlq: link.neighborLinkQuality.toFixed(3),
cost: link.linkCost.toFixed(3),
snr: link.snr,
signal: link.signal,
noise: link.noise,
color: color,
snr_color: snr_color,
dfgcolor: defaultgw_color,
proto: link.proto,
});
}
var nt = document.getElementById('olsr_neigh_table');
if (nt) {
var s =
'<div class="tr cbi-section-table-cell">' +
'<div class="th cbi-section-table-cell">Neighbour IP</div>' +
'<div class="th cbi-section-table-cell">Hostname</div>' +
'<div class="th cbi-section-table-cell">Interface</div>' +
'<div class="th cbi-section-table-cell">Local interface IP</div>' +
'<div class="th cbi-section-table-cell">LQ</div>' +
'<div class="th cbi-section-table-cell">NLQ</div>' +
'<div class="th cbi-section-table-cell">ETX</div>' +
'<div class="th cbi-section-table-cell">SNR</div>' +
'</div>';
for (var idx = 0; idx < rv.length; idx++) {
var neigh = rv[idx];
if (neigh.proto == '6') {
s +=
'<div class="tr cbi-section-table-row cbi-rowstyle-' +
(1 + (idx % 2)) +
' proto-' +
neigh.proto +
'">' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.dfgcolor +
'"><a href="http://[' +
neigh.rip +
']/cgi-bin-status.html">' +
neigh.rip +
'</a></div>';
} else {
s +=
'<div class="tr cbi-section-table-row cbi-rowstyle-' +
(1 + (idx % 2)) +
' proto-' +
neigh.proto +
'">' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.dfgcolor +
'"><a href="http://' +
neigh.rip +
'/cgi-bin-status.html">' +
neigh.rip +
'</a></div>';
}
if (neigh.hn) {
s += '<div class="td cbi-section-table-cell left" style="background-color:' + neigh.dfgcolor + '"><a href="http://' + neigh.hn + '/cgi-bin-status.html">' + neigh.hn + '</a></div>';
} else {
s += '<div class="td cbi-section-table-cell left" style="background-color:' + neigh.dfgcolor + '">?</div>';
}
s +=
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.dfgcolor +
'">' +
(neigh?.ifn?.interface ?? '?') +
'</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.dfgcolor +
'">' +
neigh.lip +
'</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.dfgcolor +
'">' +
neigh.lq +
'</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.dfgcolor +
'">' +
neigh.nlq +
'</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.color +
'">' +
neigh.cost +
'</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
neigh.snr_color +
'" title="Signal: ' +
neigh.signal +
' Noise: ' +
neigh.noise +
'">' +
(neigh.snr || '?') +
'</div>' +
'</div>';
}
nt.innerHTML = s;
}
var i = 1;
for (var k = 0; k < neigh_res.length; k++) {
var link = neigh_res[k];
link.linkCost = parseInt(link.linkCost) || 0;
if (link.linkCost === 4194304) {
link.linkCost = 0;
}
color = etx_color(link.linkCost);
snr_color = snr_colors(link.snr);
if (link.snr === 0) {
link.snr = '?';
}
var defaultgw_color = '';
if (link.defaultgw === 1) {
defaultgw_color = '#ffff99';
}
var tr = E(
'div',
{
'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + link.proto,
},
[
link.proto === '6'
? E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
[
E(
'a',
{
'href': 'http://[' + link.remoteIP + ']/cgi-bin-status.html',
},
link.remoteIP
),
]
)
: E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
[
E(
'a',
{
'href': 'http://' + link.remoteIP + '/cgi-bin-status.html',
},
link.remoteIP
),
]
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
[E('a', { 'href': 'http://%q/cgi-bin-status.html'.format(link.hostname) }, '%h'.format(link.hostname))]
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
link?.interface?.interface ?? '?'
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
link.localIP
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
[E('div', {}, link.linkQuality.toFixed(3))]
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + defaultgw_color,
},
[E('div', {}, link.neighborLinkQuality.toFixed(3))]
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + color,
},
[E('div', {}, link.linkCost.toFixed(3))]
),
E(
'div',
{
'class': 'td cbi-section-table-cell left',
'style': 'background-color:' + snr_color,
'title': 'Signal: ' + link.signal + ' Noise: ' + link.noise,
},
link.snr
),
]
);
table.appendChild(tr);
i = (i % 2) + 1;
}
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of currently established OLSR connections')), table]);
var h2 = E('h2', { 'name': 'content' }, _('OLSR connections'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrLegend = E('div', {}, [
E('h3', {}, [_('Legend') + ':']),
E('ul', {}, [
E('li', {}, [E('strong', {}, [_('LQ: ')]), _('Success rate of packages received from the neighbour')]),
E('li', {}, [E('strong', {}, [_('NLQ: ')]), _('Success rate of packages sent to the neighbour')]),
E('li', {}, [E('strong', {}, [_('ETX: ')]), _('Expected retransmission count')]),
E('li', { 'style': 'list-style: none' }, [
E('ul', {}, [
E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (ETX < 2)')]),
E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (2 < ETX < 4)')]),
E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (4 < ETX < 10)')]),
E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (ETX > 10)')]),
]),
]),
E('li', {}, [E('strong', {}, [_('SNR: ')]), _('Signal Noise Ratio in dB')]),
E('li', { 'style': 'list-style: none' }, [
E('ul', {}, [
E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (SNR > 30)')]),
E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (30 > SNR > 20)')]),
E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (20 > SNR > 5)')]),
E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (SNR < 5)')]),
]),
]),
]),
]);
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', {
type: 'text/javascript',
src: L.resource('common/common_js.js'),
});
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrLegend, statusOlsrCommonJs]);
return result;
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -0,0 +1,330 @@
'use strict';
'require uci';
'require view';
'require poll';
'require network';
'require rpc';
'require ui';
function etx_color(etx) {
let color = '#bb3333';
if (etx === 0) {
color = '#bb3333';
} else if (etx < 2) {
color = '#00cc00';
} else if (etx < 4) {
color = '#ffcb05';
} else if (etx < 10) {
color = '#ff6600';
}
return color;
}
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
callGetHosts: rpc.declare({
object: 'olsrinfo',
method: 'hosts',
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_routes: function () {
var self = this;
return new Promise(function (resolve, reject) {
self
.fetch_jsoninfo('routes')
.then(function ([data, has_v4, has_v6, error]) {
if (error) {
reject(error);
}
var resolveVal = uci.get('luci_olsr', 'general', 'resolve');
function compare(a, b) {
if (a.proto === b.proto) {
return a.rtpMetricCost < b.rtpMetricCost;
} else {
return a.proto < b.proto;
}
}
var modifiedData;
self
.callGetHosts()
.then(function (res) {
function matchHostnames(ip) {
var lines = res.hosts.split('\n');
for (var i = 0; i < lines.length; i++) {
var ipandhostname = lines[i].trim().split(/\s+/);
if (ipandhostname[0] === ip) {
return ipandhostname[1];
}
}
return null;
}
modifiedData = data.map(function (v) {
if (resolveVal === '1') {
var hostname = matchHostnames(v.gateway);
if (hostname) {
v.hostname = hostname;
}
}
return v;
});
modifiedData.sort(compare);
var result = { routes: modifiedData, has_v4: has_v4, has_v6: has_v6 };
resolve(result);
})
.catch(function (err) {
modifiedData = data;
console.error(err);
});
})
.catch(function (err) {
reject(err);
});
});
},
load: function () {
var self = this;
poll.add(function () {
self.render();
}, 5);
return Promise.all([uci.load('olsrd'), uci.load('luci_olsr')]);
},
render: function () {
var routes_res;
var has_v4;
var has_v6;
var self = this;
return this.action_routes()
.then(function (result) {
routes_res = result.routes;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var table = E('div', { 'class': 'table cbi-section-table', 'id': 'olsrd_routes' }, [
E('div', { 'class': 'tr cbi-section-table-cell' }, [
E('div', { 'class': 'th cbi-section-table-cell' }, _('Announced network')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('OLSR gateway')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Interface')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Metric')),
E('div', { 'class': 'th cbi-section-table-cell' }, 'ETX'),
]),
]);
var rv = [];
for (var k = 0; k < routes_res.length; k++) {
var route = routes_res[k];
var ETX = (parseFloat(route.etx) || 0).toFixed(3);
rv.push({
hostname: route.hostname,
dest: route.destination,
genmask: route.genmask,
gw: route.gateway,
interface: route.networkInterface,
metric: route.metric,
etx: ETX,
color: etx_color(parseFloat(ETX)),
});
}
var rt = document.getElementById('olsrd_routes');
if (rt) {
var s =
'<div class="tr cbi-section-table-cell">' +
'<div class="th cbi-section-table-cell">Announced network</div>' +
'<div class="th cbi-section-table-cell">OLSR gateway</div>' +
'<div class="th cbi-section-table-cell">Interface</div>' +
'<div class="th cbi-section-table-cell">Metric</div>' +
'<div class="th cbi-section-table-cell">ETX</div>' +
'</div>';
for (var idx = 0; idx < rv.length; idx++) {
var route = rv[idx];
s +=
'<div class="tr cbi-section-table-row cbi-rowstyle-' +
(1 + (idx % 2)) +
' proto-' +
route.proto +
'">' +
'<div class="td cbi-section-table-cell left">' +
route.dest +
'/' +
route.genmask +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
'<a href="http://' +
route.gw +
'/cgi-bin-status.html">' +
route.gw +
'</a>';
if (route.hostname) {
if (route.proto == '6') {
s += ' / <a href="http://[%q]/cgi-bin-status.html">%h</a>'.format(route.hostname, route.hostname || '')
} else {
s += ' / <a href="http://%q/cgi-bin-status.html">%h</a>'.format(route.hostname, route.hostname || '');
}
}
s +=
'</div>' +
'<div class="td cbi-section-table-cell left">' +
route.interface +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
route.metric +
'</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:' +
route.color +
'">' +
(route.etx || '?') +
'</div>' +
'</div>';
}
rt.innerHTML = s;
}
var i = 1;
for (var k = 0; k < routes_res.length; k++) {
var route = routes_res[k];
var ETX = parseInt(route.etx) || 0;
var color = etx_color(ETX);
var tr = E('div', { 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + route.proto }, [
E('div', { 'class': 'td cbi-section-table-cell left' }, route.destination + '/' + route.genmask),
E('div', { 'class': 'td cbi-section-table-cell left' }, [
route.proto === '6' ? E('a', { 'href': 'http://[' + route.gateway + ']/cgi-bin-status.html' }, route.gateway) : E('a', { 'href': 'http://' + route.gateway + '/cgi-bin-status.html' }, route.gateway),
route.hostname ? E('span', {}, [' / ', E('a', { 'href': 'http://%q/cgi-bin-status.html'.format(route.hostname) }, '%h'.format(route.hostname))]) : '',
]),
E('div', { 'class': 'td cbi-section-table-cell left' }, route.networkInterface),
E('div', { 'class': 'td cbi-section-table-cell left' }, route.metric),
E('div', { 'class': 'td cbi-section-table-cell left', 'style': 'background-color:' + color }, [ETX.toFixed(3)]),
]);
table.appendChild(tr);
i = (i % 2) + 1;
}
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of currently known routes to other OLSR nodes')), table]);
var h2 = E('h2', { 'name': 'content' }, _('Known OLSR routes'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrLegend = E('div', {}, [
E('h3', {}, [_('Legend') + ':']),
E('ul', {}, [
E('li', {}, [E('strong', {}, [_('LQ: ')]), _('Success rate of packages received from the neighbour')]),
E('li', {}, [E('strong', {}, [_('NLQ: ')]), _('Success rate of packages sent to the neighbour')]),
E('li', {}, [E('strong', {}, [_('ETX: ')]), _('Expected retransmission count')]),
E('li', { 'style': 'list-style: none' }, [
E('ul', {}, [
E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (ETX < 2)')]),
E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (2 < ETX < 4)')]),
E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (4 < ETX < 10)')]),
E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (ETX > 10)')]),
]),
]),
E('li', {}, [E('strong', {}, [_('SNR: ')]), _('Signal Noise Ratio in dB')]),
E('li', { 'style': 'list-style: none' }, [
E('ul', {}, [
E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (SNR > 30)')]),
E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (30 > SNR > 20)')]),
E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (20 > SNR > 5)')]),
E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (SNR < 5)')]),
]),
]),
]),
]);
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', { 'type': 'text/javascript', 'src': L.resource('common/common_js.js') });
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrLegend, statusOlsrCommonJs]);
return result;
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -0,0 +1,283 @@
'use strict';
'require uci';
'require view';
'require poll';
'require rpc';
'require ui';
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_smartgw: function () {
var self = this;
return new Promise(function (resolve, reject) {
self
.fetch_jsoninfo('gateways')
.then(function ([data, has_v4, has_v6, error]) {
if (error) {
reject(error);
}
function compare(a, b) {
if (a.proto === b.proto) {
return a.cost < b.cost;
} else {
return a.proto < b.proto;
}
}
data.ipv4.sort(compare);
data.ipv6.sort(compare);
var result = { gws: data, has_v4: has_v4, has_v6: has_v6 };
resolve(result);
})
.catch(function (err) {
reject(err);
});
});
},
load: function () {
var self = this;
poll.add(function () {
self.render();
}, 5);
return Promise.all([uci.load('olsrd'), uci.load('luci_olsr')]);
},
render: function () {
var gws_res;
var has_v4;
var has_v6;
var self = this;
return this.action_smartgw()
.then(function (result) {
gws_res = result.gws;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [
E('legend', {}, _('Overview of smart gateways in this network')),
E('div', { 'class': 'table cbi-section-table', 'id': 'olsrd_smartgw' }, [
E('div', { 'class': 'tr cbi-section-table-titles' }, [
E('div', { 'class': 'th cbi-section-table-cell' }, _('Gateway')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Selected')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('ETX')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Hops')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Uplink')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Downlink')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('IPv4')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('IPv6')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Prefix')),
]),
]),
]);
var has_smartgw;
uci.sections('olsrd', 'olsrd', function (s) {
if (s.SmartGateway && s.SmartGateway === 'yes') {
has_smartgw = true;
}
});
var rv = [];
for (var k = 0; k < gws_res.ipv4.length; k++) {
var gw = gws_res.ipv4[k];
gw.cost = parseFloat(gw.cost) / 1024 || 0;
if (gw.cost >= 100) {
gw.cost = 0;
}
rv.push({
proto: gw.IPv4 ? '4' : '6',
originator: gw.originator,
selected: gw.selected ? luci.i18n.translate('yes') : luci.i18n.translate('no'),
cost: gw.cost > 0 ? gw.cost.toFixed(3) : luci.i18n.translate('infinite'),
hops: gw.hops,
uplink: gw.uplink,
downlink: gw.downlink,
v4: gw.IPv4 ? luci.i18n.translate('yes') : luci.i18n.translate('no'),
v6: gw.IPv6 ? luci.i18n.translate('yes') : luci.i18n.translate('no'),
prefix: gw.prefix,
});
}
var smartgwdiv = document.getElementById('olsrd_smartgw');
if (smartgwdiv) {
var s =
'<div class="tr cbi-section-table-titles">' +
'<div class="th cbi-section-table-cell">Gateway</div>' +
'<div class="th cbi-section-table-cell">Selected</div>' +
'<div class="th cbi-section-table-cell">ETX></div>' +
'<div class="th cbi-section-table-cell">Hops></div>' +
'<div class="th cbi-section-table-cell">Uplink</div>' +
'<div class="th cbi-section-table-cell">Downlink</div>' +
'<div class="th cbi-section-table-cell">IPv4</div>' +
'<div class="th cbi-section-table-cell">IPv6</div>' +
'<div class="th cbi-section-table-cell">Prefix</div>' +
'</div>';
for (var idx = 0; idx < rv.length; idx++) {
var smartgw = rv[idx];
var linkgw;
s += '<div class="tr cbi-section-table-row cbi-rowstyle-' + (1 + (idx % 2)) + ' proto-' + smartgw.proto + '">';
if (smartgw.proto == '6') {
linkgw = '<a href="http://[' + smartgw.originator + ']/cgi-bin-status.html">' + smartgw.originator + '</a>';
} else {
linkgw = '<a href="http://' + smartgw.originator + '/cgi-bin-status.html">' + smartgw.originator + '</a>';
}
s +=
'<div class="td cbi-section-table-cell left">' +
linkgw +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.selected +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.cost +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.hops +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.uplink +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.downlink +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.v4 +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.v6 +
'</div>' +
'<div class="td cbi-section-table-cell left">' +
smartgw.prefix +
'</div>';
s += '</div>';
}
smartgwdiv.innerHTML = s;
}
var i = 1;
if (has_smartgw) {
for (var k = 0; k < gws_res.ipv4.length; k++) {
var gw = gws_res.ipv4[k];
gw.cost = parseInt(gw.cost) / 1024 || 0;
if (gw.cost >= 100) {
gw.cost = 0;
}
var tr = E('div', { 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + gw.proto }, [
gw.proto === '6'
? E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://[' + gw.originator + ']/cgi-bin-status.html' }, gw.originator)])
: E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://' + gw.originator + '/cgi-bin-status.html' }, gw.originator)]),
E('div', { 'class': 'td cbi-section-table-cell left' }, [gw.selected ? luci.i18n.translate('yes') : luci.i18n.translate('no')]),
E('div', { 'class': 'td cbi-section-table-cell left' }, [gw.cost > 0 ? string.format('%.3f', gw.cost) : luci.i18n.translate('infinite')]),
E('div', { 'class': 'td cbi-section-table-cell left' }, gw.hops),
E('div', { 'class': 'td cbi-section-table-cell left' }, gw.uplink),
E('div', { 'class': 'td cbi-section-table-cell left' }, gw.downlink),
E('div', { 'class': 'td cbi-section-table-cell left' }, gw.IPv4 ? luci.i18n.translate('yes') : luci.i18n.translate('no')),
E('div', { 'class': 'td cbi-section-table-cell left' }, gw.IPv6 ? luci.i18n.translate('yes') : luci.i18n.translate('no')),
E('div', { 'class': 'td cbi-section-table-cell left' }, gw.prefix),
]);
fieldset.appendChild(tr);
i = (i % 2) + 1;
}
var h2 = E('h2', { 'name': 'content' }, _('SmartGW announcements'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', { 'type': 'text/javascript', 'src': L.resource('common/common_js.js') });
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrCommonJs]);
return result;
} else {
return E('h2', {}, _('SmartGateway is not configured on this system'));
}
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});

View file

@ -0,0 +1,218 @@
'use strict';
'require uci';
'require view';
'require poll';
'require rpc';
'require ui';
function etx_color(etx) {
let color = '#bb3333';
if (etx === 0) {
color = '#bb3333';
} else if (etx < 2) {
color = '#00cc00';
} else if (etx < 4) {
color = '#ffcb05';
} else if (etx < 10) {
color = '#ff6600';
}
return color;
}
return view.extend({
callGetJsonStatus: rpc.declare({
object: 'olsrinfo',
method: 'getjsondata',
params: ['otable', 'v4_port', 'v6_port'],
}),
fetch_jsoninfo: function (otable) {
var jsonreq4 = '';
var jsonreq6 = '';
var v4_port = parseInt(uci.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
var v6_port = parseInt(uci.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
var json;
var self = this;
return new Promise(function (resolve, reject) {
L.resolveDefault(self.callGetJsonStatus(otable, v4_port, v6_port), {})
.then(function (res) {
json = res;
jsonreq4 = JSON.parse(json.jsonreq4);
jsonreq6 = json.jsonreq6 !== '' ? JSON.parse(json.jsonreq6) : [];
var jsondata4 = {};
var jsondata6 = {};
var data4 = [];
var data6 = [];
var has_v4 = false;
var has_v6 = false;
if (jsonreq4 === '' && jsonreq6 === '') {
window.location.href = 'error_olsr';
reject([null, 0, 0, true]);
return;
}
if (jsonreq4 !== '') {
has_v4 = true;
jsondata4 = jsonreq4 || {};
if (otable === 'status') {
data4 = jsondata4;
} else {
data4 = jsondata4[otable] || [];
}
for (var i = 0; i < data4.length; i++) {
data4[i]['proto'] = '4';
}
}
if (jsonreq6 !== '') {
has_v6 = true;
jsondata6 = jsonreq6 || {};
if (otable === 'status') {
data6 = jsondata6;
} else {
data6 = jsondata6[otable] || [];
}
for (var j = 0; j < data6.length; j++) {
data6[j]['proto'] = '6';
}
}
for (var k = 0; k < data6.length; k++) {
data4.push(data6[k]);
}
resolve([data4, has_v4, has_v6, false]);
})
.catch(function (err) {
console.error(err);
reject([null, 0, 0, true]);
});
});
},
action_topology: function () {
var self = this;
return new Promise(function (resolve, reject) {
self
.fetch_jsoninfo('topology')
.then(function ([data, has_v4, has_v6, error]) {
if (error) {
reject(error);
}
function compare(a, b) {
if (a.proto === b.proto) {
return a.tcEdgeCost < b.tcEdgeCost;
} else {
return a.proto < b.proto;
}
}
data.sort(compare);
var result = { routes: data, has_v4: has_v4, has_v6: has_v6 };
resolve(result);
})
.catch(function (err) {
reject(err);
});
});
},
load: function () {
return Promise.all([uci.load('olsrd'), uci.load('luci_olsr')]);
},
render: function () {
var routes_res;
var has_v4;
var has_v6;
return this.action_topology()
.then(function (result) {
routes_res = result.routes;
has_v4 = result.has_v4;
has_v6 = result.has_v6;
var table = E('div', { 'class': 'table cbi-section-table' }, [
E('div', { 'class': 'tr cbi-section-table-titles' }, [
E('div', { 'class': 'th cbi-section-table-cell' }, _('OLSR node')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('Last hop')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('LQ')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('NLQ')),
E('div', { 'class': 'th cbi-section-table-cell' }, _('ETX')),
]),
]);
var i = 1;
for (var k = 0; k < routes_res.length; k++) {
var route = routes_res[k];
var cost = (parseInt(route.tcEdgeCost) || 0).toFixed(3);
var color = etx_color(parseInt(cost));
var lq = (parseInt(route.linkQuality) || 0).toFixed(3);
var nlq = (parseInt(route.neighborLinkQuality) || 0).toFixed(3);
var tr = E('div', { 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i + ' proto-' + route.proto }, [
route.proto === '6'
? E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://[' + route.destinationIP + ']/cgi-bin-status.html' }, route.destinationIP)])
: E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://' + route.destinationIP + '/cgi-bin-status.html' }, route.destinationIP)]),
route.proto === '6'
? E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://[' + route.lastHopIP + ']/cgi-bin-status.html' }, route.lastHopIP)])
: E('div', { 'class': 'td cbi-section-table-cell left' }, [E('a', { 'href': 'http://' + route.lastHopIP + '/cgi-bin-status.html' }, route.lastHopIP)]),
E('div', { 'class': 'td cbi-section-table-cell left' }, lq),
E('div', { 'class': 'td cbi-section-table-cell left' }, nlq),
E('div', { 'class': 'td cbi-section-table-cell left', 'style': 'background-color:' + color }, cost),
]);
table.appendChild(tr);
i = (i % 2) + 1;
}
var fieldset = E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of currently known OLSR nodes')), table]);
var h2 = E('h2', { 'name': 'content' }, _('Active OLSR nodes'));
var divToggleButtons = E('div', { 'id': 'togglebuttons' });
var statusOlsrLegend = E('div', {}, [
E('h3', {}, [_('Legend') + ':']),
E('ul', {}, [
E('li', {}, [E('strong', {}, [_('LQ: ')]), _('Success rate of packages received from the neighbour')]),
E('li', {}, [E('strong', {}, [_('NLQ: ')]), _('Success rate of packages sent to the neighbour')]),
E('li', {}, [E('strong', {}, [_('ETX: ')]), _('Expected retransmission count')]),
E('li', { style: 'list-style: none' }, [
E('ul', {}, [
E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (ETX < 2)')]),
E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (2 < ETX < 4)')]),
E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (4 < ETX < 10)')]),
E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (ETX > 10)')]),
]),
]),
E('li', {}, [E('strong', {}, [_('SNR: ')]), _('Signal Noise Ratio in dB')]),
E('li', { 'style': 'list-style: none' }, [
E('ul', {}, [
E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (SNR > 30)')]),
E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (30 > SNR > 20)')]),
E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (20 > SNR > 5)')]),
E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (SNR < 5)')]),
]),
]),
]),
]);
var statusOlsrCommonJs = null;
if (has_v4 && has_v6) {
statusOlsrCommonJs = E('script', { 'type': 'text/javascript', 'src': L.resource('common/common_js.js') });
}
var result = E([], {}, [h2, divToggleButtons, fieldset, statusOlsrLegend, statusOlsrCommonJs]);
return result;
})
.catch(function (error) {
console.error(error);
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});

View file

@ -1,412 +0,0 @@
module("luci.controller.olsr", package.seeall)
local neigh_table = nil
local ifaddr_table = nil
function index()
local ipv4,ipv6
if nixio.fs.access("/etc/config/olsrd") then
ipv4 = 1
end
if nixio.fs.access("/etc/config/olsrd6") then
ipv6 = 1
end
if not ipv4 and not ipv6 then
return
end
require("luci.model.uci")
local uci = luci.model.uci.cursor_state()
uci:foreach("olsrd", "olsrd", function(s)
if s.SmartGateway and s.SmartGateway == "yes" then has_smartgw = true end
end)
local page = node("admin", "status", "olsr")
page.target = template("status-olsr/overview")
page.title = _("OLSR")
page.subindex = true
page.acl_depends = { "luci-app-olsr" }
local page = node("admin", "status", "olsr", "json")
page.target = call("action_json")
page.title = nil
page.leaf = true
local page = node("admin", "status", "olsr", "neighbors")
page.target = call("action_neigh")
page.title = _("Neighbours")
page.subindex = true
page.order = 5
local page = node("admin", "status", "olsr", "routes")
page.target = call("action_routes")
page.title = _("Routes")
page.order = 10
local page = node("admin", "status", "olsr", "topology")
page.target = call("action_topology")
page.title = _("Topology")
page.order = 20
local page = node("admin", "status", "olsr", "hna")
page.target = call("action_hna")
page.title = _("HNA")
page.order = 30
local page = node("admin", "status", "olsr", "mid")
page.target = call("action_mid")
page.title = _("MID")
page.order = 50
if has_smartgw then
local page = node("admin", "status", "olsr", "smartgw")
page.target = call("action_smartgw")
page.title = _("SmartGW")
page.order = 60
end
local page = node("admin", "status", "olsr", "interfaces")
page.target = call("action_interfaces")
page.title = _("Interfaces")
page.order = 70
odsp = entry(
{"admin", "services", "olsrd", "display"},
cbi("olsr/olsrddisplay"), _("Display")
)
end
function action_json()
local http = require "luci.http"
local utl = require "luci.util"
local uci = require "luci.model.uci".cursor()
local jsonreq4
local jsonreq6
local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
jsonreq4 = utl.exec("(echo /all | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v4_port)
jsonreq6 = utl.exec("(echo /all | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v6_port)
http.prepare_content("application/json")
if not jsonreq4 or jsonreq4 == "" then
jsonreq4 = "{}"
end
if not jsonreq6 or jsonreq6 == "" then
jsonreq6 = "{}"
end
http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
end
local function local_mac_lookup(ipaddr)
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
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
function action_neigh(json)
local data, has_v4, has_v6, error = fetch_jsoninfo('links')
if error then
return
end
local uci = require "luci.model.uci".cursor_state()
local resolve = uci:get("luci_olsr", "general", "resolve")
local ntm = require "luci.model.network".init()
local devices = ntm:get_wifidevs()
local sys = require "luci.sys"
local assoclist = {}
local ntm = require "luci.model.network"
local ipc = require "luci.ip"
local nxo = require "nixio"
local defaultgw
ipc.routes({ family = 4, type = 1, dest_exact = "0.0.0.0/0" },
function(rt) defaultgw = rt.gw end)
local function compare(a,b)
if a.proto == b.proto then
return a.linkCost < b.linkCost
else
return a.proto < b.proto
end
end
for _, dev in ipairs(devices) do
for _, net in ipairs(dev:get_wifinets()) do
local radio = net:get_device()
assoclist[#assoclist+1] = {}
assoclist[#assoclist]['ifname'] = net:ifname()
assoclist[#assoclist]['network'] = net:network()[1]
assoclist[#assoclist]['device'] = radio and radio:name() or nil
assoclist[#assoclist]['list'] = net:assoclist()
end
end
for k, v in ipairs(data) do
local snr = 0
local signal = 0
local noise = 0
local mac = ""
local ip
local neihgt = {}
if resolve == "1" then
hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
if hostname then
v.hostname = hostname
end
end
local interface = ntm:get_status_by_address(v.localIP)
local lmac = local_mac_lookup(v.localIP)
local rmac = remote_mac_lookup(v.remoteIP)
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
if rmac == luci.ip.checkmac(assocmac) then
signal = tonumber(assot.signal)
noise = tonumber(assot.noise)
snr = (noise*-1) - (signal*-1)
end
end
end
end
if interface then
v.interface = interface
end
v.snr = snr
v.signal = signal
v.noise = noise
if rmac then
v.remoteMAC = rmac
end
if lmac then
v.localMAC = lmac
end
if defaultgw == v.remoteIP then
v.defaultgw = 1
end
end
table.sort(data, compare)
luci.template.render("status-olsr/neighbors", {links=data, has_v4=has_v4, has_v6=has_v6})
end
function action_routes()
local data, has_v4, has_v6, error = fetch_jsoninfo('routes')
if error then
return
end
local uci = require "luci.model.uci".cursor_state()
local resolve = uci:get("luci_olsr", "general", "resolve")
for k, v in ipairs(data) do
if resolve == "1" then
local hostname = nixio.getnameinfo(v.gateway, nil, 100)
if hostname then
v.hostname = hostname
end
end
end
local function compare(a,b)
if a.proto == b.proto then
return a.rtpMetricCost < b.rtpMetricCost
else
return a.proto < b.proto
end
end
table.sort(data, compare)
luci.template.render("status-olsr/routes", {routes=data, has_v4=has_v4, has_v6=has_v6})
end
function action_topology()
local data, has_v4, has_v6, error = fetch_jsoninfo('topology')
if error then
return
end
local function compare(a,b)
if a.proto == b.proto then
return a.tcEdgeCost < b.tcEdgeCost
else
return a.proto < b.proto
end
end
table.sort(data, compare)
luci.template.render("status-olsr/topology", {routes=data, has_v4=has_v4, has_v6=has_v6})
end
function action_hna()
local data, has_v4, has_v6, error = fetch_jsoninfo('hna')
if error then
return
end
local uci = require "luci.model.uci".cursor_state()
local resolve = uci:get("luci_olsr", "general", "resolve")
local function compare(a,b)
if a.proto == b.proto then
return a.genmask < b.genmask
else
return a.proto < b.proto
end
end
for k, v in ipairs(data) do
if resolve == "1" then
hostname = nixio.getnameinfo(v.gateway, nil, 100)
if hostname then
v.hostname = hostname
end
end
if v.validityTime then
v.validityTime = tonumber(string.format("%.0f", v.validityTime / 1000))
end
end
table.sort(data, compare)
luci.template.render("status-olsr/hna", {hna=data, has_v4=has_v4, has_v6=has_v6})
end
function action_mid()
local data, has_v4, has_v6, error = fetch_jsoninfo('mid')
if error then
return
end
local function compare(a,b)
if a.proto == b.proto then
return a.main.ipAddress < b.main.ipAddress
else
return a.proto < b.proto
end
end
table.sort(data, compare)
luci.template.render("status-olsr/mid", {mids=data, has_v4=has_v4, has_v6=has_v6})
end
function action_smartgw()
local data, has_v4, has_v6, error = fetch_jsoninfo('gateways')
if error then
return
end
local function compare(a,b)
if a.proto == b.proto then
return a.cost < b.cost
else
return a.proto < b.proto
end
end
table.sort(data.ipv4, compare)
table.sort(data.ipv6, compare)
luci.template.render("status-olsr/smartgw", {gws=data, has_v4=has_v4, has_v6=has_v6})
end
function action_interfaces()
local data, has_v4, has_v6, error = fetch_jsoninfo('interfaces')
local ntm = require "luci.model.network".init()
if error then
return
end
local function compare(a,b)
return a.proto < b.proto
end
for k, v in ipairs(data) do
local interface = ntm:get_status_by_address(v.olsrInterface.ipAddress)
if interface then
v.interface = interface
end
end
table.sort(data, compare)
luci.template.render("status-olsr/interfaces", {iface=data, has_v4=has_v4, has_v6=has_v6})
end
-- Internal
function fetch_jsoninfo(otable)
local uci = require "luci.model.uci".cursor_state()
local utl = require "luci.util"
local json = require "luci.json"
local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
local jsonreq4 = ""
local jsonreq6 = ""
local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
jsonreq4 = utl.exec("(echo /%s | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v4_port })
jsonreq6 = utl.exec("(echo /%s | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v6_port })
local jsondata4 = {}
local jsondata6 = {}
local data4 = {}
local data6 = {}
local has_v4 = False
local has_v6 = False
if jsonreq4 == '' and jsonreq6 == '' then
luci.template.render("status-olsr/error_olsr")
return nil, 0, 0, true
end
if jsonreq4 ~= "" then
has_v4 = 1
jsondata4 = json.decode(jsonreq4) or {}
if otable == 'status' then
data4 = jsondata4
else
data4 = jsondata4[otable] or {}
end
for k, v in ipairs(data4) do
data4[k]['proto'] = '4'
end
end
if jsonreq6 ~= "" then
has_v6 = 1
jsondata6 = json.decode(jsonreq6) or {}
if otable == 'status' then
data6 = jsondata6
else
data6 = jsondata6[otable] or {}
end
for k, v in ipairs(data6) do
data6[k]['proto'] = '6'
end
end
for k, v in ipairs(data6) do
table.insert(data4, v)
end
return data4, has_v4, has_v6, false
end

View file

@ -1,48 +0,0 @@
module("luci.controller.olsr4", package.seeall)
function index()
if not nixio.fs.access("/etc/config/olsrd") then
return
end
require("luci.model.uci")
local uci = luci.model.uci.cursor_state()
local ol = entry(
{"admin", "services", "olsrd"},
cbi("olsr/olsrd"), "OLSR IPv4"
)
ol.subindex = true
ol.acl_depends = { "luci-app-olsr" }
entry(
{"admin", "services", "olsrd", "iface"},
cbi("olsr/olsrdiface")
).leaf = true
entry(
{"admin", "services", "olsrd", "hna"},
cbi("olsr/olsrdhna"), _("HNA Announcements")
)
oplg = entry(
{"admin", "services", "olsrd", "plugins"},
cbi("olsr/olsrdplugins"), _("Plugins")
)
oplg.leaf = true
oplg.subindex = true
local uci = require("luci.model.uci").cursor()
uci:foreach("olsrd", "LoadPlugin",
function (section)
local lib = section.library
entry(
{"admin", "services", "olsrd", "plugins", lib },
cbi("olsr/olsrdplugins"),
nil --'Plugin "%s"' % lib:gsub("^olsrd_",""):gsub("%.so.+$","")
)
end
)
end

View file

@ -1,48 +0,0 @@
module("luci.controller.olsr6", package.seeall)
function index()
if not nixio.fs.access("/etc/config/olsrd6") then
return
end
require("luci.model.uci")
local uci = luci.model.uci.cursor_state()
local ol = entry(
{"admin", "services", "olsrd6"},
cbi("olsr/olsrd6"), "OLSR IPv6"
)
ol.subindex = true
ol.acl_depends = { "luci-app-olsr" }
entry(
{"admin", "services", "olsrd6", "iface"},
cbi("olsr/olsrdiface6")
).leaf = true
entry(
{"admin", "services", "olsrd6", "hna"},
cbi("olsr/olsrdhna6"), _("HNA6 Announcements")
)
oplg = entry(
{"admin", "services", "olsrd6", "plugins"},
cbi("olsr/olsrdplugins6"), _("Plugins")
)
oplg.leaf = true
oplg.subindex = true
local uci = require("luci.model.uci").cursor()
uci:foreach("olsrd6", "LoadPlugin",
function (section)
local lib = section.library
entry(
{"admin", "services", "olsrd6", "plugins", lib },
cbi("olsr/olsrdplugins6"),
nil --'Plugin "%s"' % lib:gsub("^olsrd_",""):gsub("%.so.+$","")
)
end
)
end

View file

@ -1,409 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
require("luci.tools.webadmin")
local fs = require "nixio.fs"
local util = require "luci.util"
local ip = require "luci.ip"
local has_ipip = fs.glob("/etc/modules.d/[0-9]*-ipip")()
m = Map("olsrd", translate("OLSR Daemon"),
translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
"As such it allows mesh routing for any network equipment. "..
"It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
"Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
function m.on_parse()
local has_defaults = false
m.uci:foreach("olsrd", "InterfaceDefaults",
function(s)
has_defaults = true
return false
end)
if not has_defaults then
m.uci:section("olsrd", "InterfaceDefaults")
end
end
function write_float(self, section, value)
local n = tonumber(value)
if n ~= nil then
return Value.write(self, section, "%.1f" % n)
end
end
s = m:section(TypedSection, "olsrd", translate("General settings"))
s.anonymous = true
s:tab("general", translate("General Settings"))
s:tab("lquality", translate("Link Quality Settings"))
s:tab("smartgw", translate("SmartGW"), not has_ipip and translate("Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it."))
s:tab("advanced", translate("Advanced Settings"))
ipv = s:taboption("general", ListValue, "IpVersion", translate("Internet protocol"),
translate("IP-version to use. If 6and4 is selected then one olsrd instance is started for each protocol."))
ipv:value("4", "IPv4")
ipv:value("6and4", "6and4")
poll = s:taboption("advanced", Value, "Pollrate", translate("Pollrate"),
translate("Polling rate for OLSR sockets in seconds. Default is 0.05."))
poll.optional = true
poll.datatype = "ufloat"
poll.placeholder = "0.05"
nicc = s:taboption("advanced", Value, "NicChgsPollInt", translate("Nic changes poll interval"),
translate("Interval to poll network interfaces for configuration changes (in seconds). Default is \"2.5\"."))
nicc.optional = true
nicc.datatype = "ufloat"
nicc.placeholder = "2.5"
tos = s:taboption("advanced", Value, "TosValue", translate("TOS value"),
translate("Type of service value for the IP header of control traffic. Default is \"16\"."))
tos.optional = true
tos.datatype = "uinteger"
tos.placeholder = "16"
fib = s:taboption("general", ListValue, "FIBMetric", translate("FIB metric"),
translate ("FIBMetric controls the metric value of the host-routes OLSRd sets. "..
"\"flat\" means that the metric value is always 2. This is the preferred value "..
"because it helps the Linux kernel routing to clean up older routes. "..
"\"correct\" uses the hopcount as the metric value. "..
"\"approx\" uses the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. "..
"Default is \"flat\"."))
fib:value("flat")
fib:value("correct")
fib:value("approx")
lql = s:taboption("lquality", ListValue, "LinkQualityLevel", translate("LQ level"),
translate("Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />"..
"<b>0</b> = do not use link quality<br />"..
"<b>2</b> = use link quality for MPR selection and routing<br />"..
"Default is \"2\""))
lql:value("2")
lql:value("0")
lqage = s:taboption("lquality", Value, "LinkQualityAging", translate("LQ aging"),
translate("Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values "..
"mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)"))
lqage.optional = true
lqage:depends("LinkQualityLevel", "2")
lqa = s:taboption("lquality", ListValue, "LinkQualityAlgorithm", translate("LQ algorithm"),
translate("Link quality algorithm (only for lq level 2).<br />"..
"<b>etx_float</b>: floating point ETX with exponential aging<br />"..
"<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />"..
"<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />"..
"<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />"..
"Defaults to \"etx_ff\""))
lqa.optional = true
lqa:value("etx_ff")
lqa:value("etx_fpm")
lqa:value("etx_float")
lqa:value("etx_ffeth")
lqa:depends("LinkQualityLevel", "2")
lqa.optional = true
lqfish = s:taboption("lquality", Flag, "LinkQualityFishEye", translate("LQ fisheye"),
translate("Fisheye mechanism for TCs (checked means on). Default is \"on\""))
lqfish.default = "1"
lqfish.optional = true
hyst = s:taboption("lquality", Flag, "UseHysteresis", translate("Use hysteresis"),
translate("Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing "..
"but delays neighbor registration. Defaults is \"yes\""))
hyst.default = "yes"
hyst.enabled = "yes"
hyst.disabled = "no"
hyst:depends("LinkQualityLevel", "0")
hyst.optional = true
hyst.rmempty = true
port = s:taboption("general", Value, "OlsrPort", translate("Port"),
translate("The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535."))
port.optional = true
port.default = "698"
port.rmempty = true
mainip = s:taboption("general", Value, "MainIp", translate("Main IP"),
translate("Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. "..
"Default is 0.0.0.0, which triggers usage of the IP of the first interface."))
mainip.optional = true
mainip.rmempty = true
mainip.datatype = "ipaddr"
mainip.placeholder = "0.0.0.0"
sgw = s:taboption("smartgw", Flag, "SmartGateway", translate("Enable"), translate("Enable SmartGateway. If it is disabled, then " ..
"all other SmartGateway parameters are ignored. Default is \"no\"."))
sgw.default="no"
sgw.enabled="yes"
sgw.disabled="no"
sgw.rmempty = true
sgwnat = s:taboption("smartgw", Flag, "SmartGatewayAllowNAT", translate("Allow gateways with NAT"), translate("Allow the selection of an outgoing IPv4 gateway with NAT"))
sgwnat:depends("SmartGateway", "yes")
sgwnat.default="yes"
sgwnat.enabled="yes"
sgwnat.disabled="no"
sgwnat.optional = true
sgwnat.rmempty = true
sgwuplink = s:taboption("smartgw", ListValue, "SmartGatewayUplink", translate("Announce uplink"), translate("Which kind of uplink is exported to the other mesh nodes. " ..
"An uplink is detected by looking for a local HNA of 0.0.0.0/0, ::ffff:0:0/96 or 2000::/3. Default setting is \"both\"."))
sgwuplink:value("none")
sgwuplink:value("ipv4")
sgwuplink:value("ipv6")
sgwuplink:value("both")
sgwuplink:depends("SmartGateway", "yes")
sgwuplink.default="both"
sgwuplink.optional = true
sgwuplink.rmempty = true
sgwulnat = s:taboption("smartgw", Flag, "SmartGatewayUplinkNAT", translate("Uplink uses NAT"), translate("If this Node uses NAT for connections to the internet. " ..
"Default is \"yes\"."))
sgwulnat:depends("SmartGatewayUplink", "ipv4")
sgwulnat:depends("SmartGatewayUplink", "both")
sgwulnat.default="yes"
sgwulnat.enabled="yes"
sgwulnat.disabled="no"
sgwnat.optional = true
sgwnat.rmempty = true
sgwspeed = s:taboption("smartgw", Value, "SmartGatewaySpeed", translate("Speed of the uplink"), translate("Specifies the speed of "..
"the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is \"128 1024\"."))
sgwspeed:depends("SmartGatewayUplink", "ipv4")
sgwspeed:depends("SmartGatewayUplink", "ipv6")
sgwspeed:depends("SmartGatewayUplink", "both")
sgwspeed.optional = true
sgwspeed.rmempty = true
sgwprefix = s:taboption("smartgw", Value, "SmartGatewayPrefix", translate("IPv6-Prefix of the uplink"), translate("This can be used " ..
"to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " ..
"use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. " ..
"Default is \"::/0\" (no prefix)."))
sgwprefix:depends("SmartGatewayUplink", "ipv6")
sgwprefix:depends("SmartGatewayUplink", "both")
sgwprefix.optional = true
sgwprefix.rmempty = true
willingness = s:taboption("advanced", ListValue, "Willingness", translate("Willingness"),
translate("The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is \"3\"."))
for i=0,7 do
willingness:value(i)
end
willingness.optional = true
willingness.default = "3"
natthr = s:taboption("advanced", Value, "NatThreshold", translate("NAT threshold"),
translate("If the route to the current gateway is to be changed, the ETX value of this gateway is "..
"multiplied with this value before it is compared to the new one. "..
"The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />"..
"<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />"..
"Defaults to \"1.0\"."))
for i=1,0.1,-0.1 do
natthr:value(i)
end
natthr:depends("LinkQualityAlgorithm", "etx_ff")
natthr:depends("LinkQualityAlgorithm", "etx_float")
natthr:depends("LinkQualityAlgorithm", "etx_fpm")
natthr.default = "1.0"
natthr.optional = true
natthr.write = write_float
i = m:section(TypedSection, "InterfaceDefaults", translate("Interfaces Defaults"))
i.anonymous = true
i.addremove = false
i:tab("general", translate("General Settings"))
i:tab("addrs", translate("IP Addresses"))
i:tab("timing", translate("Timing and Validity"))
mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
translate("Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
"Valid modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
mode:value("mesh")
mode:value("ether")
mode.optional = true
mode.rmempty = true
weight = i:taboption("general", Value, "Weight", translate("Weight"),
translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
"Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
"but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
"<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
"For any other value of LinkQualityLevel, the interface ETX value is used instead."))
weight.optional = true
weight.datatype = "uinteger"
weight.placeholder = "0"
lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
"It is only used when LQ-Level is greater than 0. Examples:<br />"..
"reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />"..
"reduce LQ to all nodes on this interface by 20%: default 0.8"))
lqmult.optional = true
lqmult.rmempty = true
lqmult.cast = "table"
lqmult.placeholder = "default 1.0"
function lqmult.validate(self, value)
for _, v in pairs(value) do
if v ~= "" then
local val = util.split(v, " ")
local host = val[1]
local mult = val[2]
if not host or not mult then
return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) separated by space.")
end
if not (host == "default" or ip.IPv4(host) or ip.IPv6(host)) then
return nil, translate("Can only be a valid IPv4 or IPv6 address or 'default'")
end
if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
end
if not mult:match("[0-1]%.[0-9]+") then
return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
end
end
end
return value
end
ip4b = i:taboption("addrs", Value, "Ip4Broadcast", translate("IPv4 broadcast"),
translate("IPv4 broadcast address for outgoing OLSR packets. One useful example would be 255.255.255.255. "..
"Default is \"0.0.0.0\", which triggers the usage of the interface broadcast IP."))
ip4b.optional = true
ip4b.datatype = "ip4addr"
ip4b.placeholder = "0.0.0.0"
ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
ip6m.optional = true
ip6m.datatype = "ip6addr"
ip6m.placeholder = "FF02::6D"
ip4s = i:taboption("addrs", Value, "IPv4Src", translate("IPv4 source"),
translate("IPv4 src address for outgoing OLSR packages. Default is \"0.0.0.0\", which triggers usage of the interface IP."))
ip4s.optional = true
ip4s.datatype = "ip4addr"
ip4s.placeholder = "0.0.0.0"
ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
"Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
ip6s.optional = true
ip6s.datatype = "ip6addr"
ip6s.placeholder = "0::/0"
hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
hi.optional = true
hi.datatype = "ufloat"
hi.placeholder = "5.0"
hi.write = write_float
hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
hv.optional = true
hv.datatype = "ufloat"
hv.placeholder = "40.0"
hv.write = write_float
ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
ti.optional = true
ti.datatype = "ufloat"
ti.placeholder = "2.0"
ti.write = write_float
tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
tv.optional = true
tv.datatype = "ufloat"
tv.placeholder = "256.0"
tv.write = write_float
mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
mi.optional = true
mi.datatype = "ufloat"
mi.placeholder = "18.0"
mi.write = write_float
mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
mv.optional = true
mv.datatype = "ufloat"
mv.placeholder = "324.0"
mv.write = write_float
ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
ai.optional = true
ai.datatype = "ufloat"
ai.placeholder = "18.0"
ai.write = write_float
av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
av.optional = true
av.datatype = "ufloat"
av.placeholder = "108.0"
av.write = write_float
ifs = m:section(TypedSection, "Interface", translate("Interfaces"))
ifs.addremove = true
ifs.anonymous = true
ifs.extedit = luci.dispatcher.build_url("admin/services/olsrd/iface/%s")
ifs.template = "cbi/tblsection"
function ifs.create(...)
local sid = TypedSection.create(...)
luci.http.redirect(ifs.extedit % sid)
end
ign = ifs:option(Flag, "ignore", translate("Enable"))
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
network = ifs:option(DummyValue, "interface", translate("Network"))
network.template = "cbi/network_netinfo"
mode = ifs:option(DummyValue, "Mode", translate("Mode"))
function mode.cfgvalue(...)
return Value.cfgvalue(...) or m.uci:get_first("olsrd", "InterfaceDefaults", "Mode", "mesh")
end
hello = ifs:option(DummyValue, "_hello", translate("Hello"))
function hello.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd", section, "HelloInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HelloInterval", 5))
local v = tonumber(m.uci:get("olsrd", section, "HelloValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HelloValidityTime", 40))
return "%.01fs / %.01fs" %{ i, v }
end
tc = ifs:option(DummyValue, "_tc", translate("TC"))
function tc.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd", section, "TcInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "TcInterval", 2))
local v = tonumber(m.uci:get("olsrd", section, "TcValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "TcValidityTime", 256))
return "%.01fs / %.01fs" %{ i, v }
end
mid = ifs:option(DummyValue, "_mid", translate("MID"))
function mid.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd", section, "MidInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "MidInterval", 18))
local v = tonumber(m.uci:get("olsrd", section, "MidValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "MidValidityTime", 324))
return "%.01fs / %.01fs" %{ i, v }
end
hna = ifs:option(DummyValue, "_hna", translate("HNA"))
function hna.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd", section, "HnaInterval")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HnaInterval", 18))
local v = tonumber(m.uci:get("olsrd", section, "HnaValidityTime")) or tonumber(m.uci:get_first("olsrd", "InterfaceDefaults", "HnaValidityTime", 108))
return "%.01fs / %.01fs" %{ i, v }
end
return m

View file

@ -1,390 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
require("luci.tools.webadmin")
local fs = require "nixio.fs"
local util = require "luci.util"
local ip = require "luci.ip"
local has_ipip = fs.glob("/etc/modules.d/[0-9]*-ipip")()
m = Map("olsrd6", translate("OLSR Daemon"),
translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
"As such it allows mesh routing for any network equipment. "..
"It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
"Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
function m.on_parse()
local has_defaults = false
m.uci:foreach("olsrd6", "InterfaceDefaults",
function(s)
has_defaults = true
return false
end)
if not has_defaults then
m.uci:section("olsrd6", "InterfaceDefaults")
end
end
function write_float(self, section, value)
local n = tonumber(value)
if n ~= nil then
return Value.write(self, section, "%.1f" % n)
end
end
s = m:section(TypedSection, "olsrd6", translate("General settings"))
s.anonymous = true
s:tab("general", translate("General Settings"))
s:tab("lquality", translate("Link Quality Settings"))
s:tab("smartgw", translate("SmartGW"), not has_ipip and translate("Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it."))
s:tab("advanced", translate("Advanced Settings"))
poll = s:taboption("advanced", Value, "Pollrate", translate("Pollrate"),
translate("Polling rate for OLSR sockets in seconds. Default is 0.05."))
poll.optional = true
poll.datatype = "ufloat"
poll.placeholder = "0.05"
nicc = s:taboption("advanced", Value, "NicChgsPollInt", translate("Nic changes poll interval"),
translate("Interval to poll network interfaces for configuration changes (in seconds). Default is \"2.5\"."))
nicc.optional = true
nicc.datatype = "ufloat"
nicc.placeholder = "2.5"
tos = s:taboption("advanced", Value, "TosValue", translate("TOS value"),
translate("Type of service value for the IP header of control traffic. Default is \"16\"."))
tos.optional = true
tos.datatype = "uinteger"
tos.placeholder = "16"
fib = s:taboption("general", ListValue, "FIBMetric", translate("FIB metric"),
translate ("FIBMetric controls the metric value of the host-routes OLSRd sets. "..
"\"flat\" means that the metric value is always 2. This is the preferred value "..
"because it helps the Linux kernel routing to clean up older routes. "..
"\"correct\" uses the hopcount as the metric value. "..
"\"approx\" uses the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. "..
"Default is \"flat\"."))
fib:value("flat")
fib:value("correct")
fib:value("approx")
lql = s:taboption("lquality", ListValue, "LinkQualityLevel", translate("LQ level"),
translate("Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />"..
"<b>0</b> = do not use link quality<br />"..
"<b>2</b> = use link quality for MPR selection and routing<br />"..
"Default is \"2\""))
lql:value("2")
lql:value("0")
lqage = s:taboption("lquality", Value, "LinkQualityAging", translate("LQ aging"),
translate("Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values "..
"mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)"))
lqage.optional = true
lqage:depends("LinkQualityLevel", "2")
lqa = s:taboption("lquality", ListValue, "LinkQualityAlgorithm", translate("LQ algorithm"),
translate("Link quality algorithm (only for lq level 2).<br />"..
"<b>etx_float</b>: floating point ETX with exponential aging<br />"..
"<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />"..
"<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />"..
"<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />"..
"Defaults to \"etx_ff\""))
lqa.optional = true
lqa:value("etx_ff")
lqa:value("etx_fpm")
lqa:value("etx_float")
lqa:value("etx_ffeth")
lqa:depends("LinkQualityLevel", "2")
lqa.optional = true
lqfish = s:taboption("lquality", Flag, "LinkQualityFishEye", translate("LQ fisheye"),
translate("Fisheye mechanism for TCs (checked means on). Default is \"on\""))
lqfish.default = "1"
lqfish.optional = true
hyst = s:taboption("lquality", Flag, "UseHysteresis", translate("Use hysteresis"),
translate("Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing "..
"but delays neighbor registration. Defaults is \"yes\""))
hyst.default = "yes"
hyst.enabled = "yes"
hyst.disabled = "no"
hyst:depends("LinkQualityLevel", "0")
hyst.optional = true
hyst.rmempty = true
port = s:taboption("general", Value, "OlsrPort", translate("Port"),
translate("The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535."))
port.optional = true
port.default = "698"
port.rmempty = true
mainip = s:taboption("general", Value, "MainIp", translate("Main IP"),
translate("Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. "..
"Default is ::, which triggers usage of the IP of the first interface."))
mainip.optional = true
mainip.rmempty = true
mainip.datatype = "ipaddr"
mainip.placeholder = "::"
sgw = s:taboption("smartgw", Flag, "SmartGateway", translate("Enable"), translate("Enable SmartGateway. If it is disabled, then " ..
"all other SmartGateway parameters are ignored. Default is \"no\"."))
sgw.default="no"
sgw.enabled="yes"
sgw.disabled="no"
sgw.rmempty = true
sgwnat = s:taboption("smartgw", Flag, "SmartGatewayAllowNAT", translate("Allow gateways with NAT"), translate("Allow the selection of an outgoing IPv4 gateway with NAT"))
sgwnat:depends("SmartGateway", "yes")
sgwnat.default="yes"
sgwnat.enabled="yes"
sgwnat.disabled="no"
sgwnat.optional = true
sgwnat.rmempty = true
sgwuplink = s:taboption("smartgw", ListValue, "SmartGatewayUplink", translate("Announce uplink"), translate("Which kind of uplink is exported to the other mesh nodes. " ..
"An uplink is detected by looking for a local HNA6 ::ffff:0:0/96 or 2000::/3. Default setting is \"both\"."))
sgwuplink:value("none")
sgwuplink:value("ipv4")
sgwuplink:value("ipv6")
sgwuplink:value("both")
sgwuplink:depends("SmartGateway", "yes")
sgwuplink.default="both"
sgwuplink.optional = true
sgwuplink.rmempty = true
sgwulnat = s:taboption("smartgw", Flag, "SmartGatewayUplinkNAT", translate("Uplink uses NAT"), translate("If this Node uses NAT for connections to the internet. " ..
"Default is \"yes\"."))
sgwulnat:depends("SmartGatewayUplink", "ipv4")
sgwulnat:depends("SmartGatewayUplink", "both")
sgwulnat.default="yes"
sgwulnat.enabled="yes"
sgwulnat.disabled="no"
sgwnat.optional = true
sgwnat.rmempty = true
sgwspeed = s:taboption("smartgw", Value, "SmartGatewaySpeed", translate("Speed of the uplink"), translate("Specifies the speed of "..
"the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is \"128 1024\"."))
sgwspeed:depends("SmartGatewayUplink", "ipv4")
sgwspeed:depends("SmartGatewayUplink", "ipv6")
sgwspeed:depends("SmartGatewayUplink", "both")
sgwspeed.optional = true
sgwspeed.rmempty = true
sgwprefix = s:taboption("smartgw", Value, "SmartGatewayPrefix", translate("IPv6-Prefix of the uplink"), translate("This can be used " ..
"to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " ..
"use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. " ..
"Default is \"::/0\" (no prefix)."))
sgwprefix:depends("SmartGatewayUplink", "ipv6")
sgwprefix:depends("SmartGatewayUplink", "both")
sgwprefix.optional = true
sgwprefix.rmempty = true
willingness = s:taboption("advanced", ListValue, "Willingness", translate("Willingness"),
translate("The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is \"3\"."))
for i=0,7 do
willingness:value(i)
end
willingness.optional = true
willingness.default = "3"
natthr = s:taboption("advanced", Value, "NatThreshold", translate("NAT threshold"),
translate("If the route to the current gateway is to be changed, the ETX value of this gateway is "..
"multiplied with this value before it is compared to the new one. "..
"The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />"..
"<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />"..
"Defaults to \"1.0\"."))
for i=1,0.1,-0.1 do
natthr:value(i)
end
natthr:depends("LinkQualityAlgorithm", "etx_ff")
natthr:depends("LinkQualityAlgorithm", "etx_float")
natthr:depends("LinkQualityAlgorithm", "etx_fpm")
natthr.default = "1.0"
natthr.optional = true
natthr.write = write_float
i = m:section(TypedSection, "InterfaceDefaults", translate("Interfaces Defaults"))
i.anonymous = true
i.addremove = false
i:tab("general", translate("General Settings"))
i:tab("addrs", translate("IP Addresses"))
i:tab("timing", translate("Timing and Validity"))
mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
translate("Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
"Valid modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
mode:value("mesh")
mode:value("ether")
mode.optional = true
mode.rmempty = true
weight = i:taboption("general", Value, "Weight", translate("Weight"),
translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
"Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
"but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
"<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
"For any other value of LinkQualityLevel, the interface ETX value is used instead."))
weight.optional = true
weight.datatype = "uinteger"
weight.placeholder = "0"
lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
"It is only used when LQ-Level is greater than 0. Examples:<br />"..
"reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />"..
"reduce LQ to all nodes on this interface by 20%: default 0.8"))
lqmult.optional = true
lqmult.rmempty = true
lqmult.cast = "table"
lqmult.placeholder = "default 1.0"
function lqmult.validate(self, value)
for _, v in pairs(value) do
if v ~= "" then
local val = util.split(v, " ")
local host = val[1]
local mult = val[2]
if not host or not mult then
return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) separated by space.")
end
if not (host == "default" or ip.IPv6(host)) then
return nil, translate("Can only be a valid IPv6 address or 'default'")
end
if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
end
if not mult:match("[0-1]%.[0-9]+") then
return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
end
end
end
return value
end
ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
ip6m.optional = true
ip6m.datatype = "ip6addr"
ip6m.placeholder = "FF02::6D"
ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
"Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
ip6s.optional = true
ip6s.datatype = "ip6addr"
ip6s.placeholder = "0::/0"
hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
hi.optional = true
hi.datatype = "ufloat"
hi.placeholder = "5.0"
hi.write = write_float
hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
hv.optional = true
hv.datatype = "ufloat"
hv.placeholder = "40.0"
hv.write = write_float
ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
ti.optional = true
ti.datatype = "ufloat"
ti.placeholder = "2.0"
ti.write = write_float
tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
tv.optional = true
tv.datatype = "ufloat"
tv.placeholder = "256.0"
tv.write = write_float
mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
mi.optional = true
mi.datatype = "ufloat"
mi.placeholder = "18.0"
mi.write = write_float
mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
mv.optional = true
mv.datatype = "ufloat"
mv.placeholder = "324.0"
mv.write = write_float
ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
ai.optional = true
ai.datatype = "ufloat"
ai.placeholder = "18.0"
ai.write = write_float
av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
av.optional = true
av.datatype = "ufloat"
av.placeholder = "108.0"
av.write = write_float
ifs = m:section(TypedSection, "Interface", translate("Interfaces"))
ifs.addremove = true
ifs.anonymous = true
ifs.extedit = luci.dispatcher.build_url("admin/services/olsrd6/iface/%s")
ifs.template = "cbi/tblsection"
function ifs.create(...)
local sid = TypedSection.create(...)
luci.http.redirect(ifs.extedit % sid)
end
ign = ifs:option(Flag, "ignore", translate("Enable"))
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
network = ifs:option(DummyValue, "interface", translate("Network"))
network.template = "cbi/network_netinfo"
mode = ifs:option(DummyValue, "Mode", translate("Mode"))
function mode.cfgvalue(...)
return Value.cfgvalue(...) or m.uci:get_first("olsrd6", "InterfaceDefaults", "Mode", "mesh")
end
hello = ifs:option(DummyValue, "_hello", translate("Hello"))
function hello.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd6", section, "HelloInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HelloInterval", 5))
local v = tonumber(m.uci:get("olsrd6", section, "HelloValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HelloValidityTime", 40))
return "%.01fs / %.01fs" %{ i, v }
end
tc = ifs:option(DummyValue, "_tc", translate("TC"))
function tc.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd6", section, "TcInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "TcInterval", 2))
local v = tonumber(m.uci:get("olsrd6", section, "TcValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "TcValidityTime", 256))
return "%.01fs / %.01fs" %{ i, v }
end
mid = ifs:option(DummyValue, "_mid", translate("MID"))
function mid.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd6", section, "MidInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "MidInterval", 18))
local v = tonumber(m.uci:get("olsrd6", section, "MidValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "MidValidityTime", 324))
return "%.01fs / %.01fs" %{ i, v }
end
hna = ifs:option(DummyValue, "_hna", translate("HNA"))
function hna.cfgvalue(self, section)
local i = tonumber(m.uci:get("olsrd6", section, "HnaInterval")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HnaInterval", 18))
local v = tonumber(m.uci:get("olsrd6", section, "HnaValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HnaValidityTime", 108))
return "%.01fs / %.01fs" %{ i, v }
end
return m

View file

@ -1,14 +0,0 @@
-- Copyright 2011 Manuel Munz <freifunk at somakoma de>
-- Licensed to the public under the Apache License 2.0.
m = Map("luci_olsr", translate("OLSR - Display Options"))
s = m:section(TypedSection, "olsr")
s.anonymous = true
res = s:option(Flag, "resolve", translate("Resolve"),
translate("Resolve hostnames on status pages. It is generally safe to allow this, but if you use public IPs and have unstable DNS-Setup then those pages will load really slow. In this case disable it here."))
res.default = "0"
res.optional = true
return m

View file

@ -1,45 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
-- Licensed to the public under the Apache License 2.0.
local uci = require "luci.model.uci".cursor()
local ipv = uci:get_first("olsrd", "olsrd", "IpVersion", "4")
mh = Map("olsrd", translate("OLSR - HNA-Announcements"), translate("Hosts in an OLSR routed network can announce connectivity " ..
"to external networks using HNA messages."))
if ipv == "6and4" or ipv == "4" then
hna4 = mh:section(TypedSection, "Hna4", translate("Hna4"), translate("Both values must use the dotted decimal notation."))
hna4.addremove = true
hna4.anonymous = true
hna4.template = "cbi/tblsection"
net4 = hna4:option(Value, "netaddr", translate("Network address"))
net4.datatype = "ip4addr"
net4.placeholder = "10.11.12.13"
net4.default = "10.11.12.13"
msk4 = hna4:option(Value, "netmask", translate("Netmask"))
msk4.datatype = "ip4addr"
msk4.placeholder = "255.255.255.255"
msk4.default = "255.255.255.255"
end
if ipv == "6and4" or ipv == "6" then
hna6 = mh:section(TypedSection, "Hna6", translate("Hna6"), translate("IPv6 network must be given in full notation, " ..
"prefix must be in CIDR notation."))
hna6.addremove = true
hna6.anonymous = true
hna6.template = "cbi/tblsection"
net6 = hna6:option(Value, "netaddr", translate("Network address"))
net6.datatype = "ip6addr"
net6.placeholder = "fec0:2200:106:0:0:0:0:0"
net6.default = "fec0:2200:106:0:0:0:0:0"
msk6 = hna6:option(Value, "prefix", translate("Prefix"))
msk6.datatype = "range(0,128)"
msk6.placeholder = "128"
msk6.default = "128"
end
return mh

View file

@ -1,25 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
-- Licensed to the public under the Apache License 2.0.
local uci = require "luci.model.uci".cursor()
mh = Map("olsrd6", translate("OLSR - HNA6-Announcements"), translate("Hosts in an OLSR routed network can announce connectivity " ..
"to external networks using HNA6 messages."))
hna6 = mh:section(TypedSection, "Hna6", translate("Hna6"), translate("IPv6 network must be given in full notation, " ..
"prefix must be in CIDR notation."))
hna6.addremove = true
hna6.anonymous = true
hna6.template = "cbi/tblsection"
net6 = hna6:option(Value, "netaddr", translate("Network address"))
net6.datatype = "ip6addr"
net6.placeholder = "fec0:2200:106:0:0:0:0:0"
net6.default = "fec0:2200:106:0:0:0:0:0"
msk6 = hna6:option(Value, "prefix", translate("Prefix"))
msk6.datatype = "range(0,128)"
msk6.placeholder = "128"
msk6.default = "128"
return mh

View file

@ -1,177 +0,0 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local util = require "luci.util"
local ip = require "luci.ip"
function write_float(self, section, value)
local n = tonumber(value)
if n ~= nil then
return Value.write(self, section, "%.1f" % n)
end
end
m = Map("olsrd", translate("OLSR Daemon - Interface"),
translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
"As such it allows mesh routing for any network equipment. "..
"It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
"Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
m.redirect = luci.dispatcher.build_url("admin/services/olsrd")
if not arg[1] or m.uci:get("olsrd", arg[1]) ~= "Interface" then
luci.http.redirect(m.redirect)
return
end
i = m:section(NamedSection, arg[1], "Interface", translate("Interface"))
i.anonymous = true
i.addremove = false
i:tab("general", translate("General Settings"))
i:tab("addrs", translate("IP Addresses"))
i:tab("timing", translate("Timing and Validity"))
ign = i:taboption("general", Flag, "ignore", translate("Enable"),
translate("Enable this interface."))
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
network = i:taboption("general", Value, "interface", translate("Network"),
translate("The interface OLSRd should serve."))
network.template = "cbi/network_netlist"
network.widget = "radio"
network.nocreate = true
mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
translate("Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
"Valid modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
mode:value("mesh")
mode:value("ether")
mode.optional = true
mode.rmempty = true
weight = i:taboption("general", Value, "Weight", translate("Weight"),
translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
"Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
"but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
"<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
"For any other value of LinkQualityLevel, the interface ETX value is used instead."))
weight.optional = true
weight.datatype = "uinteger"
weight.placeholder = "0"
lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
"It is only used when LQ-Level is greater than 0. Examples:<br />"..
"reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />"..
"reduce LQ to all nodes on this interface by 20%: default 0.8"))
lqmult.optional = true
lqmult.rmempty = true
lqmult.cast = "table"
lqmult.placeholder = "default 1.0"
function lqmult.validate(self, value)
for _, v in pairs(value) do
if v ~= "" then
local val = util.split(v, " ")
local host = val[1]
local mult = val[2]
if not host or not mult then
return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) separated by space.")
end
if not (host == "default" or ip.IPv4(host) or ip.IPv6(host)) then
return nil, translate("Can only be a valid IPv4 or IPv6 address or 'default'")
end
if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
end
if not mult:match("[0-1]%.[0-9]+") then
return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
end
end
end
return value
end
ip4b = i:taboption("addrs", Value, "Ip4Broadcast", translate("IPv4 broadcast"),
translate("IPv4 broadcast address for outgoing OLSR packets. One useful example would be 255.255.255.255. "..
"Default is \"0.0.0.0\", which triggers the usage of the interface broadcast IP."))
ip4b.optional = true
ip4b.datatype = "ip4addr"
ip4b.placeholder = "0.0.0.0"
ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
ip6m.optional = true
ip6m.datatype = "ip6addr"
ip6m.placeholder = "FF02::6D"
ip4s = i:taboption("addrs", Value, "IPv4Src", translate("IPv4 source"),
translate("IPv4 src address for outgoing OLSR packages. Default is \"0.0.0.0\", which triggers usage of the interface IP."))
ip4s.optional = true
ip4s.datatype = "ip4addr"
ip4s.placeholder = "0.0.0.0"
ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
"Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
ip6s.optional = true
ip6s.datatype = "ip6addr"
ip6s.placeholder = "0::/0"
hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
hi.optional = true
hi.datatype = "ufloat"
hi.placeholder = "5.0"
hi.write = write_float
hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
hv.optional = true
hv.datatype = "ufloat"
hv.placeholder = "40.0"
hv.write = write_float
ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
ti.optional = true
ti.datatype = "ufloat"
ti.placeholder = "2.0"
ti.write = write_float
tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
tv.optional = true
tv.datatype = "ufloat"
tv.placeholder = "256.0"
tv.write = write_float
mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
mi.optional = true
mi.datatype = "ufloat"
mi.placeholder = "18.0"
mi.write = write_float
mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
mv.optional = true
mv.datatype = "ufloat"
mv.placeholder = "324.0"
mv.write = write_float
ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
ai.optional = true
ai.datatype = "ufloat"
ai.placeholder = "18.0"
ai.write = write_float
av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
av.optional = true
av.datatype = "ufloat"
av.placeholder = "108.0"
av.write = write_float
return m

View file

@ -1,164 +0,0 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local util = require "luci.util"
local ip = require "luci.ip"
function write_float(self, section, value)
local n = tonumber(value)
if n ~= nil then
return Value.write(self, section, "%.1f" % n)
end
end
m = Map("olsrd6", translate("OLSR Daemon - Interface"),
translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
"As such it allows mesh routing for any network equipment. "..
"It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
"Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
m.redirect = luci.dispatcher.build_url("admin/services/olsrd6")
if not arg[1] or m.uci:get("olsrd6", arg[1]) ~= "Interface" then
luci.http.redirect(m.redirect)
return
end
i = m:section(NamedSection, arg[1], "Interface", translate("Interface"))
i.anonymous = true
i.addremove = false
i:tab("general", translate("General Settings"))
i:tab("addrs", translate("IP Addresses"))
i:tab("timing", translate("Timing and Validity"))
ign = i:taboption("general", Flag, "ignore", translate("Enable"),
translate("Enable this interface."))
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
network = i:taboption("general", Value, "interface", translate("Network"),
translate("The interface OLSRd should serve."))
network.template = "cbi/network_netlist"
network.widget = "radio"
network.nocreate = true
mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
translate("Interface mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
"Valid modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
mode:value("mesh")
mode:value("ether")
mode.optional = true
mode.rmempty = true
weight = i:taboption("general", Value, "Weight", translate("Weight"),
translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
"Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
"but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
"<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
"For any other value of LinkQualityLevel, the interface ETX value is used instead."))
weight.optional = true
weight.datatype = "uinteger"
weight.placeholder = "0"
lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
"It is only used when LQ-Level is greater than 0. Examples:<br />"..
"reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />"..
"reduce LQ to all nodes on this interface by 20%: default 0.8"))
lqmult.optional = true
lqmult.rmempty = true
lqmult.cast = "table"
lqmult.placeholder = "default 1.0"
function lqmult.validate(self, value)
for _, v in pairs(value) do
if v ~= "" then
local val = util.split(v, " ")
local host = val[1]
local mult = val[2]
if not host or not mult then
return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) separated by space.")
end
if not (host == "default" or ip.IPv6(host)) then
return nil, translate("Can only be a valid IPv6 address or 'default'")
end
if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
end
if not mult:match("[0-1]%.[0-9]+") then
return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
end
end
end
return value
end
ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
ip6m.optional = true
ip6m.datatype = "ip6addr"
ip6m.placeholder = "FF02::6D"
ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
"Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
ip6s.optional = true
ip6s.datatype = "ip6addr"
ip6s.placeholder = "0::/0"
hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
hi.optional = true
hi.datatype = "ufloat"
hi.placeholder = "5.0"
hi.write = write_float
hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
hv.optional = true
hv.datatype = "ufloat"
hv.placeholder = "40.0"
hv.write = write_float
ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
ti.optional = true
ti.datatype = "ufloat"
ti.placeholder = "2.0"
ti.write = write_float
tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
tv.optional = true
tv.datatype = "ufloat"
tv.placeholder = "256.0"
tv.write = write_float
mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
mi.optional = true
mi.datatype = "ufloat"
mi.placeholder = "18.0"
mi.write = write_float
mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
mv.optional = true
mv.datatype = "ufloat"
mv.placeholder = "324.0"
mv.write = write_float
ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
ai.optional = true
ai.datatype = "ufloat"
ai.placeholder = "18.0"
ai.write = write_float
av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
av.optional = true
av.datatype = "ufloat"
av.placeholder = "108.0"
av.write = write_float
return m

View file

@ -1,260 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local ip = require "luci.ip"
local fs = require "nixio.fs"
if arg[1] then
mp = Map("olsrd", translate("OLSR - Plugins"))
p = mp:section(TypedSection, "LoadPlugin", translate("Plugin configuration"))
p:depends("library", arg[1])
p.anonymous = true
ign = p:option(Flag, "ignore", translate("Enable"))
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
lib = p:option(DummyValue, "library", translate("Library"))
lib.default = arg[1]
local function Range(x,y)
local t = {}
for i = x, y do t[#t+1] = i end
return t
end
local function Cidr2IpMask(val)
if val then
for i = 1, #val do
local cidr = ip.IPv4(val[i]) or ip.IPv6(val[i])
if cidr then
val[i] = cidr:network():string() .. " " .. cidr:mask():string()
end
end
return val
end
end
local function IpMask2Cidr(val)
if val then
for i = 1, #val do
local ip, mask = val[i]:gmatch("([^%s]+)%s+([^%s]+)")()
local cidr
if ip and mask and ip:match(":") then
cidr = ip.IPv6(ip, mask)
elseif ip and mask then
cidr = ip.IPv4(ip, mask)
end
if cidr then
val[i] = cidr:string()
end
end
return val
end
end
local knownPlParams = {
["olsrd_bmf"] = {
{ Value, "BmfInterface", "bmf0" },
{ Value, "BmfInterfaceIp", "10.10.10.234/24" },
{ Flag, "DoLocalBroadcast", "no" },
{ Flag, "CapturePacketsOnOlsrInterfaces", "yes" },
{ ListValue, "BmfMechanism", { "UnicastPromiscuous", "Broadcast" } },
{ Value, "BroadcastRetransmitCount", "2" },
{ Value, "FanOutLimit", "4" },
{ DynamicList, "NonOlsrIf", "br-lan" }
},
["olsrd_dyn_gw"] = {
{ Value, "Interval", "40" },
{ DynamicList, "Ping", "141.1.1.1" },
{ DynamicList, "HNA", "192.168.80.0/24", IpMask2Cidr, Cidr2IpMask }
},
["olsrd_httpinfo"] = {
{ Value, "port", "80" },
{ DynamicList, "Host", "163.24.87.3" },
{ DynamicList, "Net", "0.0.0.0/0", Cidr2IpMask }
},
["olsrd_nameservice"] = {
{ DynamicList, "name", "my-name.mesh" },
{ DynamicList, "hosts", "1.2.3.4 name-for-other-interface.mesh" },
{ Value, "suffix", ".olsr" },
{ Value, "hosts_file", "/path/to/hosts_file" },
{ Value, "add_hosts", "/path/to/file" },
{ Value, "dns_server", "141.1.1.1" },
{ Value, "resolv_file", "/path/to/resolv.conf" },
{ Value, "interval", "120" },
{ Value, "timeout", "240" },
{ Value, "lat", "12.123" },
{ Value, "lon", "12.123" },
{ Value, "latlon_file", "/var/run/latlon.js" },
{ Value, "latlon_infile", "/var/run/gps.txt" },
{ Value, "sighup_pid_file", "/var/run/dnsmasq.pid" },
{ Value, "name_change_script", "/usr/local/bin/announce_new_hosts.sh" },
{ DynamicList, "service", "http://me.olsr:80|tcp|my little homepage" },
{ Value, "services_file", "/var/run/services_olsr" },
{ Value, "services_change_script", "/usr/local/bin/announce_new_services.sh" },
{ DynamicList, "mac", "xx:xx:xx:xx:xx:xx[,0-255]" },
{ Value, "macs_file", "/path/to/macs_file" },
{ Value, "macs_change_script", "/path/to/script" }
},
["olsrd_quagga"] = {
{ StaticList, "redistribute", {
"system", "kernel", "connect", "static", "rip", "ripng", "ospf",
"ospf6", "isis", "bgp", "hsls"
} },
{ ListValue, "ExportRoutes", { "only", "both" } },
{ Flag, "LocalPref", "true" },
{ Value, "Distance", Range(0,255) }
},
["olsrd_secure"] = {
{ Value, "Keyfile", "/etc/private-olsr.key" }
},
["olsrd_txtinfo"] = {
{ Value, "accept", "127.0.0.1" }
},
["olsrd_jsoninfo"] = {
{ Value, "accept", "127.0.0.1" },
{ Value, "port", "9090" },
{ Value, "UUIDFile", "/etc/olsrd/olsrd.uuid" },
},
["olsrd_watchdog"] = {
{ Value, "file", "/var/run/olsrd.watchdog" },
{ Value, "interval", "30" }
},
["olsrd_mdns"] = {
{ DynamicList, "NonOlsrIf", "lan" }
},
["olsrd_p2pd"] = {
{ DynamicList, "NonOlsrIf", "lan" },
{ Value, "P2pdTtl", "10" }
},
["olsrd_arprefresh"] = {},
["olsrd_dot_draw"] = {},
["olsrd_dyn_gw_plain"] = {},
["olsrd_pgraph"] = {},
["olsrd_tas"] = {}
}
-- build plugin options with dependencies
if knownPlParams[arg[1]] then
for _, option in ipairs(knownPlParams[arg[1]]) do
local otype, name, default, uci2cbi, cbi2uci = unpack(option)
local values
if type(default) == "table" then
values = default
default = default[1]
end
if otype == Flag then
local bool = p:option( Flag, name, name )
if default == "yes" or default == "no" then
bool.enabled = "yes"
bool.disabled = "no"
elseif default == "on" or default == "off" then
bool.enabled = "on"
bool.disabled = "off"
elseif default == "1" or default == "0" then
bool.enabled = "1"
bool.disabled = "0"
else
bool.enabled = "true"
bool.disabled = "false"
end
bool.optional = true
bool.default = default
bool:depends({ library = plugin })
else
local field = p:option( otype, name, name )
if values then
for _, value in ipairs(values) do
field:value( value )
end
end
if type(uci2cbi) == "function" then
function field.cfgvalue(self, section)
return uci2cbi(otype.cfgvalue(self, section))
end
end
if type(cbi2uci) == "function" then
function field.formvalue(self, section)
return cbi2uci(otype.formvalue(self, section))
end
end
field.optional = true
field.default = default
--field:depends({ library = arg[1] })
end
end
end
return mp
else
mpi = Map("olsrd", translate("OLSR - Plugins"))
local plugins = {}
mpi.uci:foreach("olsrd", "LoadPlugin",
function(section)
if section.library and not plugins[section.library] then
plugins[section.library] = true
end
end
)
-- create a loadplugin section for each found plugin
for v in fs.dir("/usr/lib") do
if v:sub(1, 6) == "olsrd_" then
v = string.match(v, "^(olsrd.*)%.so%..*")
if not plugins[v] then
mpi.uci:section(
"olsrd", "LoadPlugin", nil,
{ library = v, ignore = 1 }
)
end
end
end
t = mpi:section( TypedSection, "LoadPlugin", translate("Plugins") )
t.anonymous = true
t.template = "cbi/tblsection"
t.override_scheme = true
function t.extedit(self, section)
local lib = self.map:get(section, "library") or ""
return luci.dispatcher.build_url("admin", "services", "olsrd", "plugins") .. "/" .. lib
end
ign = t:option( Flag, "ignore", translate("Enabled") )
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
t:option( DummyValue, "library", translate("Library") )
return mpi
end

View file

@ -1,260 +0,0 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local ip = require "luci.ip"
local fs = require "nixio.fs"
if arg[1] then
mp = Map("olsrd6", translate("OLSR - Plugins"))
p = mp:section(TypedSection, "LoadPlugin", translate("Plugin configuration"))
p:depends("library", arg[1])
p.anonymous = true
ign = p:option(Flag, "ignore", translate("Enable"))
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
lib = p:option(DummyValue, "library", translate("Library"))
lib.default = arg[1]
local function Range(x,y)
local t = {}
for i = x, y do t[#t+1] = i end
return t
end
local function Cidr2IpMask(val)
if val then
for i = 1, #val do
local cidr = ip.IPv4(val[i]) or ip.IPv6(val[i])
if cidr then
val[i] = cidr:network():string() .. " " .. cidr:mask():string()
end
end
return val
end
end
local function IpMask2Cidr(val)
if val then
for i = 1, #val do
local ip, mask = val[i]:gmatch("([^%s]+)%s+([^%s]+)")()
local cidr
if ip and mask and ip:match(":") then
cidr = ip.IPv6(ip, mask)
elseif ip and mask then
cidr = ip.IPv4(ip, mask)
end
if cidr then
val[i] = cidr:string()
end
end
return val
end
end
local knownPlParams = {
["olsrd_bmf"] = {
{ Value, "BmfInterface", "bmf0" },
{ Value, "BmfInterfaceIp", "10.10.10.234/24" },
{ Flag, "DoLocalBroadcast", "no" },
{ Flag, "CapturePacketsOnOlsrInterfaces", "yes" },
{ ListValue, "BmfMechanism", { "UnicastPromiscuous", "Broadcast" } },
{ Value, "BroadcastRetransmitCount", "2" },
{ Value, "FanOutLimit", "4" },
{ DynamicList, "NonOlsrIf", "br-lan" }
},
["olsrd_dyn_gw"] = {
{ Value, "Interval", "40" },
{ DynamicList, "Ping", "141.1.1.1" },
{ DynamicList, "HNA", "192.168.80.0/24", IpMask2Cidr, Cidr2IpMask }
},
["olsrd_httpinfo"] = {
{ Value, "port", "80" },
{ DynamicList, "Host", "163.24.87.3" },
{ DynamicList, "Net", "0.0.0.0/0", Cidr2IpMask }
},
["olsrd_nameservice"] = {
{ DynamicList, "name", "my-name.mesh" },
{ DynamicList, "hosts", "1.2.3.4 name-for-other-interface.mesh" },
{ Value, "suffix", ".olsr" },
{ Value, "hosts_file", "/path/to/hosts_file" },
{ Value, "add_hosts", "/path/to/file" },
{ Value, "dns_server", "141.1.1.1" },
{ Value, "resolv_file", "/path/to/resolv.conf" },
{ Value, "interval", "120" },
{ Value, "timeout", "240" },
{ Value, "lat", "12.123" },
{ Value, "lon", "12.123" },
{ Value, "latlon_file", "/var/run/latlon.js.ipv6" },
{ Value, "latlon_infile", "/var/run/gps.txt" },
{ Value, "sighup_pid_file", "/var/run/dnsmasq.pid" },
{ Value, "name_change_script", "/usr/local/bin/announce_new_hosts.sh" },
{ DynamicList, "service", "http://me.olsr:80|tcp|my little homepage" },
{ Value, "services_file", "/var/run/services_olsr" },
{ Value, "services_change_script", "/usr/local/bin/announce_new_services.sh" },
{ DynamicList, "mac", "xx:xx:xx:xx:xx:xx[,0-255]" },
{ Value, "macs_file", "/path/to/macs_file" },
{ Value, "macs_change_script", "/path/to/script" }
},
["olsrd_quagga"] = {
{ StaticList, "redistribute", {
"system", "kernel", "connect", "static", "rip", "ripng", "ospf",
"ospf6", "isis", "bgp", "hsls"
} },
{ ListValue, "ExportRoutes", { "only", "both" } },
{ Flag, "LocalPref", "true" },
{ Value, "Distance", Range(0,255) }
},
["olsrd_secure"] = {
{ Value, "Keyfile", "/etc/private-olsr.key" }
},
["olsrd_txtinfo"] = {
{ Value, "accept", "::1/128" }
},
["olsrd_jsoninfo"] = {
{ Value, "accept", "::1/128" },
{ Value, "port", "9090" },
{ Value, "UUIDFile", "/etc/olsrd/olsrd.uuid.ipv6" },
},
["olsrd_watchdog"] = {
{ Value, "file", "/var/run/olsrd.watchdog.ipv6" },
{ Value, "interval", "30" }
},
["olsrd_mdns.so"] = {
{ DynamicList, "NonOlsrIf", "lan" }
},
["olsrd_p2pd.so"] = {
{ DynamicList, "NonOlsrIf", "lan" },
{ Value, "P2pdTtl", "10" }
},
["olsrd_arprefresh"] = {},
["olsrd_dot_draw"] = {},
["olsrd_dyn_gw_plain"] = {},
["olsrd_pgraph"] = {},
["olsrd_tas"] = {}
}
-- build plugin options with dependencies
if knownPlParams[arg[1]] then
for _, option in ipairs(knownPlParams[arg[1]]) do
local otype, name, default, uci2cbi, cbi2uci = unpack(option)
local values
if type(default) == "table" then
values = default
default = default[1]
end
if otype == Flag then
local bool = p:option( Flag, name, name )
if default == "yes" or default == "no" then
bool.enabled = "yes"
bool.disabled = "no"
elseif default == "on" or default == "off" then
bool.enabled = "on"
bool.disabled = "off"
elseif default == "1" or default == "0" then
bool.enabled = "1"
bool.disabled = "0"
else
bool.enabled = "true"
bool.disabled = "false"
end
bool.optional = true
bool.default = default
bool:depends({ library = plugin })
else
local field = p:option( otype, name, name )
if values then
for _, value in ipairs(values) do
field:value( value )
end
end
if type(uci2cbi) == "function" then
function field.cfgvalue(self, section)
return uci2cbi(otype.cfgvalue(self, section))
end
end
if type(cbi2uci) == "function" then
function field.formvalue(self, section)
return cbi2uci(otype.formvalue(self, section))
end
end
field.optional = true
field.default = default
--field:depends({ library = arg[1] })
end
end
end
return mp
else
mpi = Map("olsrd6", translate("OLSR - Plugins"))
local plugins = {}
mpi.uci:foreach("olsrd6", "LoadPlugin",
function(section)
if section.library and not plugins[section.library] then
plugins[section.library] = true
end
end
)
-- create a loadplugin section for each found plugin
for v in fs.dir("/usr/lib") do
if v:sub(1, 6) == "olsrd_" then
v=string.match(v, "^(olsrd_.*)%.so%..*")
if not plugins[v] then
mpi.uci:section(
"olsrd6", "LoadPlugin", nil,
{ library = v, ignore = 1 }
)
end
end
end
t = mpi:section( TypedSection, "LoadPlugin", translate("Plugins") )
t.anonymous = true
t.template = "cbi/tblsection"
t.override_scheme = true
function t.extedit(self, section)
local lib = self.map:get(section, "library") or ""
return luci.dispatcher.build_url("admin", "services", "olsrd6", "plugins") .. "/" .. lib
end
ign = t:option( Flag, "ignore", translate("Enabled") )
ign.enabled = "0"
ign.disabled = "1"
ign.rmempty = false
function ign.cfgvalue(self, section)
return Flag.cfgvalue(self, section) or "0"
end
t:option( DummyValue, "library", translate("Library") )
return mpi
end

View file

@ -1,33 +0,0 @@
-- Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
-- Licensed to the public under the Apache License 2.0.
module("luci.tools.olsr", package.seeall)
function etx_color(etx)
local color = "#bb3333"
if etx == 0 then
color = "#bb3333"
elseif etx < 2 then
color = "#00cc00"
elseif etx < 4 then
color = "#ffcb05"
elseif etx < 10 then
color = "#ff6600"
end
return color
end
function snr_color(snr)
local color = "#bb3333"
if snr == 0 then
color = "#bb3333"
elseif snr > 30 then
color = "#00cc00"
elseif snr > 20 then
color = "#ffcb05"
elseif snr > 5 then
color = "#ff6600"
end
return color
end

View file

@ -1,35 +0,0 @@
<% if has_v4 and has_v6 then %>
<script type="text/javascript">//<![CDATA[
function css(selector, property, value) {
for (var i=0; i<document.styleSheets.length;i++) {
try { document.styleSheets[i].insertRule(selector+ ' {'+property+':'+value+'}', document.styleSheets[i].cssRules.length);
} catch(err) {try { document.styleSheets[i].addRule(selector, property+':'+value);} catch(err) {}}//IE
}
}
window.onload = function() {
var buttons = '<input type="button" name="show-proto-4" id="show-proto-4" class="cbi-button cbi-button-apply" style="margin-right: 5px" value="<%:Hide IPv4%>">'
buttons += '<input type="button" name="show-proto-6" id="show-proto-6" class="cbi-button cbi-button-apply" value="<%:Hide IPv6%>">'
document.getElementById('togglebuttons').innerHTML = buttons;
var visible = true;
document.getElementById('show-proto-4').onclick = function() {
visible = !visible;
document.getElementById('show-proto-4').value = visible ? '<%:Hide IPv4%>' : '<%:Show IPv4%>';
document.getElementById('show-proto-4').className = visible ? 'cbi-button cbi-button-apply' : 'cbi-button cbi-button-reset';
css('.proto-4', 'display', visible ? 'table-row' : 'none')
};
var visible6 = true;
document.getElementById('show-proto-6').onclick = function() {
visible6 = !visible6;
document.getElementById('show-proto-6').value = visible6 ? '<%:Hide IPv6%>' : '<%:Show IPv6%>';
document.getElementById('show-proto-6').className = visible6 ? 'cbi-button cbi-button-apply' : 'cbi-button cbi-button-reset';
css('.proto-6', 'display', visible6 ? 'table-row' : 'none')
};
}
//]]></script>
<%end %>

View file

@ -1,11 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%+header%>
<h2 name="content"><%:OLSR Daemon%></h2>
<p class="error"><%:Unable to connect to the OLSR daemon!%></p>
<p><%:Make sure that OLSRd is running, the "jsoninfo" plugin is loaded, configured on port 9090 and accepts connections from "127.0.0.1".%></p>
<%+footer%>

View file

@ -1,124 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local i = 1
if luci.http.formvalue("status") == "1" then
local rv = {}
for k, hna in ipairs(hna) do
rv[#rv+1] = {
proto = hna["proto"],
destination = hna["destination"],
genmask = hna["genmask"],
gateway = hna["gateway"],
hostname = hna["hostname"],
validityTime = hna["validityTime"]
}
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
%>
<%+header%>
<script type="text/javascript">//<![CDATA[
XHR.poll(10, '<%=REQUEST_URI%>', { status: 1 },
function(x, info)
{
var hnadiv = document.getElementById('olsrd_hna');
if (hnadiv)
{
var s = '<div class="tr cbi-section-table-titles">' +
'<div class="th cbi-section-table-cell"><%:Announced network%></div>' +
'<div class="th cbi-section-table-cell"><%:OLSR gateway%></div>' +
'<div class="th cbi-section-table-cell"><%:Validity Time%></div>' +
'</div>';
for (var idx = 0; idx < info.length; idx++)
{
var hna = info[idx];
var linkgw = ''
s += '<div class="tr cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-' + hna.proto + '">'
if (hna.proto == '6') {
linkgw = '<a href="http://[' + hna.gateway + ']/cgi-bin-status.html">' + hna.gateway + '</a>'
} else {
linkgw = '<a href="http://' + hna.gateway + '/cgi-bin-status.html">' + hna.gateway + '</a>'
}
var validity;
if (hna.validityTime != undefined) {
validity = hna.validityTime + 's'
} else {
validity = '-'
}
var hostname;
if (hna.hostname != undefined) {
hostname = ' / <a href="http://' + hna.hostname + '/cgi-bin-status.html">' + hna.hostname + '</a>'
} else {
hostname = ''
}
s += String.format(
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>', hna.destination + '/' + hna.genmask, linkgw + hostname, validity
)
s += '</div>'
}
hnadiv.innerHTML = s;
}
}
);
//]]></script>
<h2 name="content"><%:Active host net announcements%></h2>
<div id="togglebuttons"></div>
<fieldset class="cbi-section">
<legend><%:Overview of currently active OLSR host net announcements%></legend>
<div class="table cbi-section-table" id="olsrd_hna">
<div class="tr cbi-section-table-titles">
<div class="th cbi-section-table-cell"><%:Announced network%></div>
<div class="th cbi-section-table-cell"><%:OLSR gateway%></div>
<div class="th cbi-section-table-cell"><%:Validity Time%></div>
</div>
<% for k, route in ipairs(hna) do %>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=hna[k].proto%>">
<div class="td cbi-section-table-cell left"><%=hna[k].destination%>/<%=hna[k].genmask%> </div>
<div class="td cbi-section-table-cell left">
<% if hna[k].proto == '6' then %>
<a href="http://[<%=hna[k].gateway%>]/cgi-bin-status.html"><%=hna[k].gateway%></a>
<% else %>
<a href="http://<%=hna[k].gateway%>/cgi-bin-status.html"><%=hna[k].gateway%></a>
<% end %>
<% if hna[k].hostname then %>
/ <a href="http://<%=hna[k].hostname%>/cgi-bin-status.html"><%=hna[k].hostname%></a>
<% end %>
</div>
<% if hna[k].validityTime then
validity = hna[k].validityTime .. 's'
else
validity = '-'
end %>
<div class="td cbi-section-table-cell left"><%=validity%></div>
</div>
<% i = ((i % 2) + 1)
end %>
</div>
</fieldset>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -1,52 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local i = 1
%>
<%+header%>
<h2 name="content"><%:Interfaces%></h2>
<div id="togglebuttons"></div>
<fieldset class="cbi-section">
<legend><%:Overview of interfaces where OLSR is running%></legend>
<div class="table cbi-section-table">
<div class="tr">
<div class="th cbi-section-table-cell"><%:Interface%></div>
<div class="th cbi-section-table-cell"><%:Device%></div>
<div class="th cbi-section-table-cell"><%:State%></div>
<div class="th cbi-section-table-cell"><%:MTU%></div>
<div class="th cbi-section-table-cell"><%:WLAN%></div>
<div class="th cbi-section-table-cell"><%:Source address%></div>
<div class="th cbi-section-table-cell"><%:Netmask%></div>
<div class="th cbi-section-table-cell"><%:Broadcast address%></div>
</div>
<% for k, iface in ipairs(iface) do %>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=iface.proto%>">
<div class="td cbi-section-table-cell left"><%=iface.interface%></div>
<div class="td cbi-section-table-cell left"><%=iface.name%></div>
<div class="td cbi-section-table-cell left"><%=iface.olsrInterface.up and luci.i18n.translate('up') or luci.i18n.translate('down')%></div>
<div class="td cbi-section-table-cell left"><%=iface.olsrInterface.mtu%></div>
<div class="td cbi-section-table-cell left"><%=iface.olsrInterface.wireless and luci.i18n.translate('yes') or luci.i18n.translate('no')%></div>
<div class="td cbi-section-table-cell left"><%=iface.olsrInterface.ipAddress%></div>
<div class="td cbi-section-table-cell left"><%=iface.olsrInterface.ipv4Address ~= '0.0.0.0' and iface.olsrInterface.ipv4Netmask%></div>
<div class="td cbi-section-table-cell left"><%=iface.olsrInterface.ipv4Address ~= '0.0.0.0' and iface.olsrInterface.ipv4Broadcast or iface.olsrInterface.ipv6Multicast%></div>
</div>
<% i = ((i % 2) + 1)
end %>
</div>
</fieldset>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -1,24 +0,0 @@
<h3><%:Legend%>:</h3>
<ul>
<li><strong>LQ: </strong><%:Success rate of packages received from the neighbour%></li>
<li><strong>NLQ: </strong><%:Success rate of packages sent to the neighbour%></li>
<li><strong>ETX: </strong><%:Expected retransmission count%></li>
<li style="list-style: none">
<ul>
<li><strong><span style="color:#00cc00"><%:Green%></span></strong>:<%:Very good (ETX < 2)%></li>
<li><strong><span style="color:#ffcb05"><%:Yellow%></span></strong>:<%:Good (2 < ETX < 4)%></li>
<li><strong><span style="color:#ff6600"><%:Orange%></span></strong>:<%:Still usable (4 < ETX < 10)%></li>
<li><strong><span style="color:#bb3333"><%:Red%></span></strong>:<%:Bad (ETX > 10)%></li>
</ul>
</li>
<li><strong>SNR: </strong><%:Signal Noise Ratio in dB%></li>
<li style="list-style: none">
<ul>
<li><strong><span style="color:#00cc00"><%:Green%></span></strong>:<%:Very good (SNR > 30)%></li>
<li><strong><span style="color:#ffcb05"><%:Yellow%></span></strong>:<%:Good (30 > SNR > 20)%></li>
<li><strong><span style="color:#ff6600"><%:Orange%></span></strong>:<%:Still usable (20 > SNR > 5)%></li>
<li><strong><span style="color:#bb3333"><%:Red%></span></strong>:<%:Bad (SNR < 5)%></li>
</ul>
</li>
</ul>

View file

@ -1,50 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local i = 1
%>
<%+header%>
<h2 name="content"><%:Active MID announcements%></h2>
<div id="togglebuttons"></div>
<fieldset class="cbi-section">
<legend><%:Overview of known multiple interface announcements%></legend>
<div class="table cbi-section-table">
<div class="tr cbi-section-table-titles">
<div class="th cbi-section-table-cell"><%:OLSR node%></div>
<div class="th cbi-section-table-cell" ><%:Secondary OLSR interfaces%></div>
</div>
<% for k, mid in ipairs(mids) do
local aliases = ''
for k,v in ipairs(mid.aliases) do
if aliases == '' then
sep = ''
else
sep = ', '
end
aliases = v.ipAddress .. sep .. aliases
end
local host = mid.main.ipAddress
if mid.proto == '6' then
host = '[' .. mid.main.ipAddress .. ']'
end
%>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=mid.proto%>">
<div class="td cbi-section-table-cell left"><a href="http://<%=host%>/cgi-bin-status.html"><%=mid.main.ipAddress%></a></div>
<div class="td cbi-section-table-cell left"><%=aliases%></div>
</div>
<% i = ((i % 2) + 1)
end %>
</div>
</fieldset>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -1,179 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local olsrtools = require "luci.tools.olsr"
local i = 1
if luci.http.formvalue("status") == "1" then
local rv = {}
for k, link in ipairs(links) do
link.linkCost = tonumber(link.linkCost) or 0
if link.linkCost == 4194304 then
link.linkCost = 0
end
local color = olsrtools.etx_color(link.linkCost)
local snr_color = olsrtools.snr_color(link.snr)
defaultgw_color = ""
if link.defaultgw == 1 then
defaultgw_color = "#ffff99"
end
rv[#rv+1] = {
rip = link.remoteIP,
hn = link.hostname,
lip = link.localIP,
ifn = link.interface,
lq = string.format("%.3f", link.linkQuality),
nlq = string.format("%.3f",link.neighborLinkQuality),
cost = string.format("%.3f", link.linkCost),
snr = link.snr,
signal = link.signal,
noise = link.noise,
color = color,
snr_color = snr_color,
dfgcolor = defaultgw_color,
proto = link.proto
}
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
%>
<%+header%>
<script type="text/javascript">//<![CDATA[
XHR.poll(10 , '<%=REQUEST_URI%>', { status: 1 },
function(x, info)
{
var nt = document.getElementById('olsr_neigh_table');
if (nt)
{
var s = '<div class="tr cbi-section-table-cell">' +
'<div class="th cbi-section-table-cell"><%:Neighbour IP%></div>' +
'<div class="th cbi-section-table-cell"><%:Hostname%></div>' +
'<div class="th cbi-section-table-cell"><%:Interface%></div>' +
'<div class="th cbi-section-table-cell"><%:Local interface IP%></div>' +
'<div class="th cbi-section-table-cell">LQ</div>' +
'<div class="th cbi-section-table-cell">NLQ</div>' +
'<div class="th cbi-section-table-cell">ETX</div>' +
'<div class="th cbi-section-table-cell">SNR</div>' +
'</div>';
for (var idx = 0; idx < info.length; idx++)
{
var neigh = info[idx];
if (neigh.proto == '6') {
s += String.format(
'<div class="tr cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-%s">' +
'<div class="td cbi-section-table-cell left" style="background-color:%s"><a href="http://[%s]/cgi-bin-status.html">%s</a></div>',
neigh.proto, neigh.dfgcolor, neigh.rip, neigh.rip
);
} else {
s += String.format(
'<div class="tr cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-%s">' +
'<div class="td cbi-section-table-cell left" style="background-color:%s"><a href="http://%s/cgi-bin-status.html">%s</a></div>',
neigh.proto, neigh.dfgcolor, neigh.rip, neigh.rip
);
}
if (neigh.hn) {
s += String.format(
'<div class="td cbi-section-table-cell left" style="background-color:%s"><a href="http://%s/cgi-bin-status.html">%s</a></div>',
neigh.dfgcolor, neigh.hn, neigh.hn
);
} else {
s += String.format(
'<div class="td cbi-section-table-cell left" style="background-color:%s">?</div>',
neigh.dfgcolor
);
}
s += String.format(
'<div class="td cbi-section-table-cell left" style="background-color:%s">%s</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:%s">%s</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:%s">%s</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:%s">%s</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:%s">%s</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:%s" title="Signal: %s Noise: %s">%s</div>' +
'</div>',
neigh.dfgcolor, neigh.ifn, neigh.dfgcolor, neigh.lip, neigh.dfgcolor, neigh.lq, neigh.dfgcolor, neigh.nlq, neigh.color, neigh.cost, neigh.snr_color, neigh.signal, neigh.noise, neigh.snr || '?'
);
}
nt.innerHTML = s;
}
}
);
//]]></script>
<h2 name="content"><%:OLSR connections%></h2>
<div id="togglebuttons"></div>
<fieldset class="cbi-section">
<legend><%:Overview of currently established OLSR connections%></legend>
<div class="table cbi-section-table" id="olsr_neigh_table">
<div class="tr cbi-section-table-cell">
<div class="th cbi-section-table-cell"><%:Neighbour IP%></div>
<div class="th cbi-section-table-cell"><%:Hostname%></div>
<div class="th cbi-section-table-cell"><%:Interface%></div>
<div class="th cbi-section-table-cell"><%:Local interface IP%></div>
<div class="th cbi-section-table-cell">LQ</div>
<div class="th cbi-section-table-cell">NLQ</div>
<div class="th cbi-section-table-cell">ETX</div>
<div class="th cbi-section-table-cell">SNR</div>
</div>
<% local i = 1
for k, link in ipairs(links) do
link.linkCost = tonumber(link.linkCost) or 0
if link.linkCost == 4194304 then
link.linkCost = 0
end
color = olsrtools.etx_color(link.linkCost)
snr_color = olsrtools.snr_color(link.snr)
if link.snr == 0 then
link.snr = '?'
end
defaultgw_color = ""
if link.defaultgw == 1 then
defaultgw_color = "#ffff99"
end
%>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=link.proto%>">
<% if link.proto == "6" then %>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><a href="http://[<%=link.remoteIP%>]/cgi-bin-status.html"><%=link.remoteIP%></a></div>
<% else %>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><a href="http://<%=link.remoteIP%>/cgi-bin-status.html"><%=link.remoteIP%></a></div>
<% end %>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><a href="http://<%=link.hostname%>/cgi-bin-status.html"><%=link.hostname%></a></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><%=link.interface%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><%=link.localIP%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><%=string.format("%.3f", link.linkQuality)%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=defaultgw_color%>"><%=string.format("%.3f", link.neighborLinkQuality)%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=color%>"><%=string.format("%.3f", link.linkCost)%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=snr_color%>" title="Signal: <%=link.signal%> Noise: <%=link.noise%>"><%=link.snr%></div>
</div>
<%
i = ((i % 2) + 1)
end %>
</div>
<br />
<%+status-olsr/legend%>
</fieldset>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -1,220 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
has_ipv4_conf = luci.model.uci.cursor():get_first("olsrd", "olsrd", "IpVersion")
has_ipv6_conf = luci.model.uci.cursor():get_first("olsrd6", "olsrd", "IpVersion")
function write_conf(conf, file)
local fs = require "nixio.fs"
if fs.access(conf) then
luci.http.header("Content-Disposition", "attachment; filename="..file)
luci.http.prepare_content("text/plain")
luci.http.write(fs.readfile(conf))
end
end
conf = luci.http.formvalue()
if conf.openwrt_v4 then
write_conf("/etc/config/olsrd", "olsrd")
return false
end
if conf.openwrt_v6 then
write_conf("/etc/config/olsrd6", "olsrd6")
return false
end
if conf.conf_v4 then
write_conf("/var/etc/olsrd.conf", "olsrd.conf")
return false
end
if conf.conf_v6 then
write_conf("/var/etc/olsrd6.conf", "olsrd6.conf")
return false
end
%>
<%+header%>
<script type="text/javascript">//<![CDATA[
XHR.poll(10, '<%=REQUEST_URI%>/json', { },
function(x, info)
{
var e;
if (! info) {
document.getElementById('error').innerHTML = '<%:Could not get any data. Make sure the jsoninfo plugin is installed and allows connections from localhost.%>';
return
}
document.getElementById('error').innerHTML = '';
if (e = document.getElementById('version'))
var version;
var date;
if (info.v4.version.version != undefined) {
version = info.v4.version.version
date = info.v4.version.date
} else if (info.v6.version.version != undefined) {
version = info.v6.version.version
date = info.v6.version.date
} else {
version = 'unknown'
date = 'unknown'
}
e.innerHTML = version + '<br />' + date;
if (e = document.getElementById('nr_neigh'))
var neigh = 0;
if (info.v4.links != undefined) {
neigh = neigh + info.v4.links.length
}
if (info.v6.links != undefined) {
neigh = neigh + info.v6.links.length
}
e.innerHTML = neigh;
if (e = document.getElementById('nr_hna'))
var hna = 0;
if (info.v4.hna != undefined) {
hna = hna + info.v4.hna.length
}
if (info.v6.hna != undefined) {
hna = hna + info.v6.hna.length
}
e.innerHTML = hna;
if (e = document.getElementById('nr_ifaces'))
var nrint = 0
if (info.v4.interfaces != undefined) {
nrint = nrint + info.v4.interfaces.length
}
if (info.v6.interfaces != undefined) {
nrint = nrint + info.v6.interfaces.length
}
e.innerHTML = nrint
if (e = document.getElementById('nr_topo'))
var topo = 0;
var nodes = [];
Array.prototype.contains = function (element) {
for (var i = 0; i < this.length; i++) {
if (this[i] == element) {
return true;
}
}
return false;
}
if (info.v4.topology != undefined) {
topo = topo + info.v4.topology.length;
for (var i = 0; i < info.v4.topology.length; i++) {
var destip = info.v4.topology[i].destinationIP
if (! nodes.contains(destip) ) {
nodes.push(destip)
}
}
}
if (info.v6.topology != undefined) {
topo = topo + info.v6.topology.length
for (var i = 0; i < info.v6.topology.length; i++) {
var destip = info.v6.topology[i].destinationIP
if (! nodes.contains(destip) ) {
nodes.push(destip)
}
}
}
e.innerHTML = topo;
if (e = document.getElementById('nr_nodes'))
e.innerHTML = nodes.length;
if (e = document.getElementById('meshfactor'))
var meshfactor = topo / nodes.length
e.innerHTML = meshfactor.toFixed(2)
}
);
//]]></script>
<div id="error" class="error"></div>
<h2 name="content">OLSR <%:Overview%></h2>
<fieldset class="cbi-section">
<legend><%:Network%></legend>
<div class="table" width="100%" cellspacing="10">
<div class="tr"><div class="td" width="33%"><%:Interfaces%></div><div class="td">
<a href="<%=REQUEST_URI%>/interfaces">
<span id="nr_ifaces">-<span>
</a>
</div></div>
<div class="tr"><div class="td" width="33%"><%:Neighbors%></div><div class="td">
<a href="<%=REQUEST_URI%>/neighbors">
<span id="nr_neigh">-</span>
</a>
</div></div>
<div class="tr"><div class="td" width="33%"><%:Nodes%></div><div class="td">
<a href="<%=REQUEST_URI%>/topology">
<span id="nr_nodes">-</span>
</a>
</div></div>
<div class="tr"><div class="td" width="33%"><%:HNA%></div><div class="td">
<a href="<%=REQUEST_URI%>/hna">
<span id="nr_hna">-</span>
</a>
</div></div>
<div class="tr"><div class="td" width="33%"><%:Links total%></div><div class="td">
<a href="<%=REQUEST_URI%>/topology">
<span id="nr_topo">-</span>
</a>
</div></div>
<div class="tr"><div class="td" width="33%"><%:Links per node (average)%></div><div class="td">
<span id="meshfactor">-</span>
</div></div>
</div>
</fieldset>
<fieldset class="cbi-section">
<legend>OLSR <%:Configuration%></legend>
<div class="table" width="100%" cellspacing="10">
<div class="tr"><div class="td" width="33%"><%:Version%></div><div class="td">
<span id="version">-<span>
</div></div>
<div class="tr"><div class="td" width="33%"><%:Download Config%></div><div class="td">
<% if has_ipv4_conf then %>
<a href="<%=REQUEST_URI%>?openwrt_v4">OpenWrt (IPv4)</a>,
<% end %>
<% if has_ipv6_conf then %>
<a href="<%=REQUEST_URI%>?openwrt_v6">OpenWrt (IPv6)</a>,
<% end %>
<% if has_ipv4_conf then %>
<a href="<%=REQUEST_URI%>?conf_v4">OLSRD (IPv4)</a>,
<% end %>
<% if has_ipv6_conf then %>
<a href="<%=REQUEST_URI%>?conf_v6">OLSRD (IPv6)</a>
<% end %>
</div></div>
</div>
</fieldset>
<%+footer%>

View file

@ -1,143 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local olsrtools = require "luci.tools.olsr"
local i = 1
if luci.http.formvalue("status") == "1" then
local rv = {}
for k, route in ipairs(routes) do
local ETX = string.format("%.3f", tonumber(route.etx) or 0)
rv[#rv+1] = {
hostname = route.hostname,
dest = route.destination,
genmask = route.genmask,
gw = route.gateway,
interface = route.networkInterface,
metric = route.metric,
etx = ETX,
color = olsrtools.etx_color(tonumber(ETX))
}
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
%>
<%+header%>
<script type="text/javascript">//<![CDATA[
XHR.poll(20, '<%=REQUEST_URI%>', { status: 1 },
function(x, info)
{
var rt = document.getElementById('olsrd_routes');
if (rt)
{
var s = '<div class="tr cbi-section-table-cell">' +
'<div class="th cbi-section-table-cell"><%:Announced network%></div>' +
'<div class="th cbi-section-table-cell"><%:OLSR gateway%></div>' +
'<div class="th cbi-section-table-cell"><%:Interface%></div>' +
'<div class="th cbi-section-table-cell"><%:Metric%></div>' +
'<div class="th cbi-section-table-cell">ETX</div>' +
'</div>';
for (var idx = 0; idx < info.length; idx++)
{
var route = info[idx];
s += String.format(
'<div class="tr cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-%s">' +
'<div class="td cbi-section-table-cell left">%s/%s</div>' +
'<div class="td cbi-section-table-cell left">' +
'<a href="http://%s/cgi-bin-status.html">%s</a>',
route.proto, route.dest, route.genmask, route.gw, route.gw
)
if (route.hostname) {
if (route.proto == '6') {
s += String.format(
' / <a href="http://[%s]/cgi-bin-status.html">%s</a>',
route.hostname, route.hostname || '?'
);
} else {
s += String.format(
' / <a href="http://%s/cgi-bin-status.html">%s</a>',
route.hostname, route.hostname || '?'
);
}
}
s += String.format(
'</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left" style="background-color:%s">%s</div>' +
'</div>',
route.interface, route.metric, route.color, route.etx || '?'
);
}
}
rt.innerHTML = s;
}
);
//]]></script>
<h2 name="content"><%:Known OLSR routes%></h2>
<div id="togglebuttons"></div>
<fieldset class="cbi-section">
<legend><%:Overview of currently known routes to other OLSR nodes%></legend>
<div class="table cbi-section-table" id="olsrd_routes">
<div class="tr cbi-section-table-cell">
<div class="th cbi-section-table-cell"><%:Announced network%></div>
<div class="th cbi-section-table-cell"><%:OLSR gateway%></div>
<div class="th cbi-section-table-cell"><%:Interface%></div>
<div class="th cbi-section-table-cell"><%:Metric%></div>
<div class="th cbi-section-table-cell">ETX</div>
</div>
<% for k, route in ipairs(routes) do
ETX = tonumber(route.etx) or '0'
color = olsrtools.etx_color(ETX)
%>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=route.proto%>">
<div class="td cbi-section-table-cell left"><%=route.destination%>/<%=route.genmask%></div>
<div class="td cbi-section-table-cell left">
<% if route.proto == '6' then %>
<a href="http://[<%=route.gateway%>]/cgi-bin-status.html"><%=route.gateway%></a>
<% else %>
<a href="http://<%=route.gateway%>/cgi-bin-status.html"><%=route.gateway%></a>
<% end %>
<% if route.hostname then %>
/ <a href="http://<%=route.Hostname%>/cgi-bin-status.html"><%=route.hostname%></a>
<% end %>
</div>
<div class="td cbi-section-table-cell left"><%=route.networkInterface%></div>
<div class="td cbi-section-table-cell left"><%=route.metric%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=color%>"><%=string.format("%.3f", ETX)%></div>
</div>
<%
i = ((i % 2) + 1)
end %>
</div>
<%+status-olsr/legend%>
</fieldset>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -1,155 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local i = 1
require("luci.model.uci")
local uci = luci.model.uci.cursor_state()
uci:foreach("olsrd", "olsrd", function(s)
if s.SmartGateway and s.SmartGateway == "yes" then has_smartgw = true end
end)
if luci.http.formvalue("status") == "1" then
local rv = {}
for k, gw in ipairs(gws.ipv4, gws.ipv6) do
gw.cost = tonumber(gw.cost)/1024 or 0
if gw.cost >= 100 then
gw.cost = 0
end
rv[#rv+1] = {
proto = gw.IPv4 and '4' or '6',
originator = gw.originator,
selected = gw.selected and luci.i18n.translate('yes') or luci.i18n.translate('no'),
cost = gw.cost > 0 and string.format("%.3f", gw.cost) or luci.i18n.translate('infinite'),
hops = gw.hops,
uplink = gw.uplink,
downlink = gw.downlink,
v4 = gw.IPv4 and luci.i18n.translate('yes') or luci.i18n.translate('no'),
v6 = gw.IPv6 and luci.i18n.translate('yes') or luci.i18n.translate('no'),
prefix = gw.prefix
}
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
return
end
%>
<%+header%>
<script type="text/javascript">//<![CDATA[
XHR.poll(10, '<%=REQUEST_URI%>', { status: 1 },
function(x, info)
{
var smartgwdiv = document.getElementById('olsrd_smartgw');
if (smartgwdiv)
{
var s = '<div class="tr cbi-section-table-titles">' +
'<div class="th cbi-section-table-cell"><%:Gateway%></div>' +
'<div class="th cbi-section-table-cell"><%:Selected%></div>' +
'<div class="th cbi-section-table-cell"><%:ETX%></div>' +
'<div class="th cbi-section-table-cell"><%:Hops%></div>' +
'<div class="th cbi-section-table-cell"><%:Uplink%></div>' +
'<div class="th cbi-section-table-cell"><%:Downlink%></div>' +
'<div class="th cbi-section-table-cell"><%:IPv4%></div>' +
'<div class="th cbi-section-table-cell"><%:IPv6%></div>' +
'<div class="th cbi-section-table-cell"><%:Prefix%></div>' +
'</div>';
for (var idx = 0; idx < info.length; idx++)
{
var smartgw = info[idx];
var linkgw;
s += '<div class="tr cbi-section-table-row cbi-rowstyle-'+(1 + (idx % 2))+' proto-' + smartgw.proto + '">'
if (smartgw.proto == '6') {
linkgw = '<a href="http://[' + smartgw.originator + ']/cgi-bin-status.html">' + smartgw.originator + '</a>'
} else {
linkgw = '<a href="http://' + smartgw.originator + '/cgi-bin-status.html">' + smartgw.originator + '</a>'
}
s += String.format(
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>' +
'<div class="td cbi-section-table-cell left">%s</div>',
linkgw, smartgw.selected, smartgw.cost, smartgw.hops, smartgw.uplink, smartgw.downlink, smartgw.v4, smartgw.v6, smartgw.prefix
)
s += '</div>'
}
smartgwdiv.innerHTML = s;
}
}
);
//]]></script>
<h2 name="content"><%:SmartGW announcements%></h2>
<div id="togglebuttons"></div>
<% if has_smartgw then %>
<fieldset class="cbi-section">
<legend><%:Overview of smart gateways in this network%></legend>
<div class="table cbi-section-table" id="olsrd_smartgw">
<div class="tr cbi-section-table-titles">
<div class="th cbi-section-table-cell"><%:Gateway%></div>
<div class="th cbi-section-table-cell"><%:Selected%></div>
<div class="th cbi-section-table-cell"><%:ETX%></div>
<div class="th cbi-section-table-cell"><%:Hops%></div>
<div class="th cbi-section-table-cell"><%:Uplink%></div>
<div class="th cbi-section-table-cell"><%:Downlink%></div>
<div class="th cbi-section-table-cell"><%:IPv4%></div>
<div class="th cbi-section-table-cell"><%:IPv6%></div>
<div class="th cbi-section-table-cell"><%:Prefix%></div>
</div>
<% for k, gw in ipairs(gws.ipv4, gws.ipv6) do
gw.cost = tonumber(gw.cost)/1024 or 0
if gw.cost >= 100 then
gw.cost = 0
end
%>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=proto%>">
<% if gw.proto == '6' then %>
<div class="td cbi-section-table-cell left"><a href="http://[<%=gw.originator%>]/cgi-bin-status.html"><%=gw.originator%></a></div>
<% else %>
<div class="td cbi-section-table-cell left"><a href="http://<%=gw.originator%>/cgi-bin-status.html"><%=gw.originator%></a></div>
<% end %>
<div class="td cbi-section-table-cell left"><%=gw.selected and luci.i18n.translate('yes') or luci.i18n.translate('no')%></div>
<div class="td cbi-section-table-cell left"><%=gw.cost > 0 and string.format("%.3f", gw.cost) or luci.i18n.translate('infinite')%></div>
<div class="td cbi-section-table-cell left"><%=gw.hops%></div>
<div class="td cbi-section-table-cell left"><%=gw.uplink%></div>
<div class="td cbi-section-table-cell left"><%=gw.downlink%></div>
<div class="td cbi-section-table-cell left"><%=gw.IPv4 and luci.i18n.translate('yes') or luci.i18n.translate('no')%></div>
<div class="td cbi-section-table-cell left"><%=gw.IPv6 and luci.i18n.translate('yes') or luci.i18n.translate('no')%></div>
<div class="td cbi-section-table-cell left"><%=gw.prefix%></div>
</div>
<% i = ((i % 2) + 1)
end %>
</div>
</fieldset>
<% else %>
<%:SmartGateway is not configured on this system.%>
<% end %>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -1,62 +0,0 @@
<%#
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
Licensed to the public under the Apache License 2.0.
-%>
<%
local i = 1
local olsrtools = require "luci.tools.olsr"
%>
<%+header%>
<h2 name="content"><%:Active OLSR nodes%></h2>
<div id="togglebuttons"></div>
<fieldset class="cbi-section">
<legend><%:Overview of currently known OLSR nodes%></legend>
<div class="table cbi-section-table">
<div class="tr cbi-section-table-titles">
<div class="th cbi-section-table-cell"><%:OLSR node%></div>
<div class="th cbi-section-table-cell"><%:Last hop%></div>
<div class="th cbi-section-table-cell"><%:LQ%></div>
<div class="th cbi-section-table-cell"><%:NLQ%></div>
<div class="th cbi-section-table-cell"><%:ETX%></div>
</div>
<% for k, route in ipairs(routes) do
local cost = string.format("%.3f", tonumber(route.tcEdgeCost) or 0)
local color = olsrtools.etx_color(tonumber(cost))
local lq = string.format("%.3f", tonumber(route.linkQuality) or 0)
local nlq = string.format("%.3f", tonumber(route.neighborLinkQuality) or 0)
%>
<div class="tr cbi-section-table-row cbi-rowstyle-<%=i%> proto-<%=route.proto%>">
<% if route.proto == "6" then %>
<div class="td cbi-section-table-cell left"><a href="http://[<%=route.destinationIP%>]/cgi-bin-status.html"><%=route.destinationIP%></a></div>
<div class="td cbi-section-table-cell left"><a href="http://[<%=route.lastHopIP%>]/cgi-bin-status.html"><%=route.lastHopIP%></a></div>
<% else %>
<div class="td cbi-section-table-cell left"><a href="http://<%=route.destinationIP%>/cgi-bin-status.html"><%=route.destinationIP%></a></div>
<div class="td cbi-section-table-cell left"><a href="http://<%=route.lastHopIP%>/cgi-bin-status.html"><%=route.lastHopIP%></a></div>
<%end%>
<div class="td cbi-section-table-cell left"><%=lq%></div>
<div class="td cbi-section-table-cell left"><%=nlq%></div>
<div class="td cbi-section-table-cell left" style="background-color:<%=color%>"><%=cost%></div>
</div>
<% i = ((i % 2) + 1)
end %>
</div>
<%+status-olsr/legend%>
</fieldset>
<%+status-olsr/common_js%>
<%+footer%>

View file

@ -0,0 +1,78 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
. /lib/functions.sh
HOSTSFILE="-1"
find_hosts_config() {
local cfg="$1"
config_get library "$cfg" library
if [ "$library" != "olsrd_nameservice" ]; then
return 1
fi
config_get hosts_file "$cfg" hosts_file
HOSTSFILE=$hosts_file
}
load_hosts() {
config_load olsrd
config_foreach find_hosts_config LoadPlugin
local hosts4=$(cat $HOSTSFILE)
HOSTSFILE=""
config_load olsrd6
config_foreach find_hosts_config LoadPlugin
if [ -f "$HOSTSFILE" ]; then
local hosts6=$(cat "$HOSTSFILE")
else
local hosts6=""
fi
local hosts="$hosts4$hosts6"
json_init
json_add_string hosts "$hosts"
json_dump
}
case "$1" in
list)
json_init
json_add_object "getjsondata"
json_add_string 'otable' 'String'
json_add_int 'v4_port' 'Integer'
json_add_int 'v6_port' 'Integer'
json_close_object
json_add_object "hasipip"
json_close_object
json_add_object "hosts"
json_close_object
json_dump
;;
call)
case "$2" in
getjsondata)
json_init
json_load "$(cat)"
json_get_var otable otable
json_get_var v4_port v4_port
json_get_var v6_port v6_port
jsonreq4=$(echo "/${otable}" | nc 127.0.0.1 "${v4_port}" | sed -n '/^[}{ ]/p' 2>/dev/null)
jsonreq6=$(echo "/${otable}" | nc ::1 "${v6_port}" | sed -n '/^[}{ ]/p' 2>/dev/null)
json_init
json_add_string "jsonreq4" "$jsonreq4"
json_add_string "jsonreq6" "$jsonreq6"
json_dump
;;
hasipip)
result=$(ls /etc/modules.d/ | grep -E "[0-9]*-ipip")
json_init
json_add_string "result" "$result"
json_dump
;;
hosts)
load_hosts
;;
esac
;;
esac

View file

@ -0,0 +1,86 @@
{
"admin/services/olsrd": {
"title": "OLSR IPv4",
"order": 5,
"depends": {
"acl": ["luci-app-olsr"]
},
"action": {
"type": "view",
"path": "olsr/frontend/olsrd"
}
},
"admin/services/olsrd/display": {
"title": "Display",
"order": 10,
"action": {
"type": "view",
"path": "olsr/frontend/olsrddisplay"
}
},
"admin/services/olsrd/iface": {
"order": 10,
"action": {
"type": "view",
"path": "olsr/frontend/olsrdiface"
}
},
"admin/services/olsrd/hna": {
"title": "HNA Announcements",
"order": 15,
"action": {
"type": "view",
"path": "olsr/frontend/olsrdhna"
}
},
"admin/services/olsrd/plugins": {
"title": "Plugins",
"order": 20,
"action": {
"type": "view",
"path": "olsr/frontend/olsrdplugins"
}
},
"admin/services/olsrd6": {
"title": "OLSR IPv6",
"order": 5,
"depends": {
"acl": ["luci-app-olsr"]
},
"action": {
"type": "view",
"path": "olsr/frontend/olsrd6"
}
},
"admin/services/olsrd6/display": {
"title": "Display",
"order": 10,
"action": {
"type": "view",
"path": "olsr/frontend/olsrddisplay"
}
},
"admin/services/olsrd6/iface": {
"order": 10,
"action": {
"type": "view",
"path": "olsr/frontend/olsrdiface6"
}
},
"admin/services/olsrd6/hna": {
"title": "HNA Announcements",
"order": 15,
"action": {
"type": "view",
"path": "olsr/frontend/olsrdhna6"
}
},
"admin/services/olsrd6/plugins": {
"title": "Plugins",
"order": 20,
"action": {
"type": "view",
"path": "olsr/frontend/olsrdplugins6"
}
}
}

View file

@ -0,0 +1,72 @@
{
"olsr": {
"title": "OLSR",
"order": 5,
"action": {
"type": "firstchild"
}
},
"olsr/neighbours": {
"title": "Neighbours",
"order": 15,
"action": {
"type": "view",
"path": "olsr/status-olsr/neighbors"
}
},
"olsr/routes": {
"title": "Routes",
"order": 20,
"action": {
"type": "view",
"path": "olsr/status-olsr/routes"
}
},
"olsr/topology": {
"title": "Topology",
"order": 25,
"action": {
"type": "view",
"path": "olsr/status-olsr/topology"
}
},
"olsr/hna": {
"title": "HNA",
"order": 30,
"action": {
"type": "view",
"path": "olsr/status-olsr/hna"
}
},
"olsr/mid": {
"title": "MID",
"order": 35,
"action": {
"type": "view",
"path": "olsr/status-olsr/mid"
}
},
"olsr/interface": {
"title": "Interface",
"order": 35,
"action": {
"type": "view",
"path": "olsr/status-olsr/interfaces"
}
},
"olsr/smartgw": {
"title": "SmartGW",
"order": 40,
"action": {
"type": "view",
"path": "olsr/status-olsr/smartgw"
}
},
"olsr/error_olsr": {
"order": 45,
"action": {
"type": "view",
"path": "olsr/status-olsr/error_olsr"
}
}
}

View file

@ -0,0 +1,20 @@
{
"unauthenticated": {
"description": "Grant read access",
"read": {
"ubus": {
"uci": ["get"],
"luci-rpc": ["*"],
"network.interface": ["dump"],
"network": ["get_proto_handlers"],
"olsrd": ["olsrd_jsoninfo"],
"olsrd6": ["olsrd_jsoninfo"],
"olsrinfo": ["getjsondata", "hasipip", "hosts"],
"file": ["read"],
"iwinfo": ["assoclist"]
},
"uci": ["luci_olsr", "olsrd", "olsrd6", "network", "network.interface"]
}
}
}

View file

@ -2,10 +2,34 @@
"luci-app-olsr": {
"description": "Grant UCI access for luci-app-olsr",
"read": {
"uci": [ "luci_olsr", "olsrd", "olsrd6" ]
"ubus": {
"luci-rpc": [
"*"
],
"olsrinfo": [
"getjsondata",
"hasipip"
]
},
"file": {
"/etc/modules.d": [
"list",
"read"
],
"/usr/lib": [ "list" ]
},
"uci": [
"luci_olsr",
"olsrd",
"olsrd6"
]
},
"write": {
"uci": [ "luci_olsr", "olsrd", "olsrd6" ]
"uci": [
"luci_olsr",
"olsrd",
"olsrd6"
]
}
}
}
}