olsrd.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. 'use strict';
  2. 'require view';
  3. 'require form';
  4. 'require fs';
  5. 'require uci';
  6. 'require ui';
  7. 'require rpc';
  8. return view.extend({
  9. callHasIpIp: rpc.declare({
  10. object: 'olsrinfo',
  11. method: 'hasipip',
  12. }),
  13. load: function () {
  14. return Promise.all([uci.load('olsrd').then(() => {
  15. var hasDefaults = false;
  16. uci.sections('olsrd', 'InterfaceDefaults', function (s) {
  17. hasDefaults = true;
  18. return false;
  19. });
  20. if (!hasDefaults) {
  21. uci.add('olsrd', 'InterfaceDefaults');
  22. }
  23. })]);
  24. },
  25. render: function () {
  26. let m, s, o;
  27. var has_ipip;
  28. m = new form.Map(
  29. 'olsrd',
  30. _('OLSR Daemon'),
  31. _(
  32. 'The OLSR daemon is an implementation of the Optimized Link State Routing protocol. ' +
  33. 'As such it allows mesh routing for any network equipment. ' +
  34. 'It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. ' +
  35. 'Visit <a href="http://www.olsr.org">olsrd.org</a> for help and documentation.'
  36. )
  37. );
  38. s = m.section(form.TypedSection, 'olsrd', _('General settings'));
  39. s.anonymous = true;
  40. s.tab('general', _('General Settings'));
  41. s.tab('lquality', _('Link Quality Settings'));
  42. this.callHasIpIp()
  43. .then(function (res) {
  44. var output = res.result;
  45. has_ipip = output.trim().length > 0;
  46. })
  47. .catch(function (err) {
  48. console.error(err);
  49. })
  50. .finally(function () {
  51. s.tab('smartgw', _('SmartGW'), !has_ipip && _('Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it.'));
  52. 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".'));
  53. sgw.default = 'no';
  54. sgw.enabled = 'yes';
  55. sgw.disabled = 'no';
  56. sgw.rmempty = true;
  57. sgw.cfgvalue = function (section_id) {
  58. return uci.get('olsrd', section_id, 'SmartGateway') || 'no';
  59. };
  60. var sgwnat = s.taboption('smartgw', form.Flag, 'SmartGatewayAllowNAT', _('Allow gateways with NAT'), _('Allow the selection of an outgoing IPv4 gateway with NAT'));
  61. sgwnat.depends('SmartGateway', 'yes');
  62. sgwnat.default = 'yes';
  63. sgwnat.enabled = 'yes';
  64. sgwnat.disabled = 'no';
  65. sgwnat.optional = true;
  66. sgwnat.rmempty = true;
  67. var sgwuplink = s.taboption(
  68. 'smartgw',
  69. form.ListValue,
  70. 'SmartGatewayUplink',
  71. _('Announce uplink'),
  72. _('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".')
  73. );
  74. sgwuplink.value('none');
  75. sgwuplink.value('ipv4');
  76. sgwuplink.value('ipv6');
  77. sgwuplink.value('both');
  78. sgwuplink.depends('SmartGateway', 'yes');
  79. sgwuplink.default = 'both';
  80. sgwuplink.optional = true;
  81. sgwuplink.rmempty = true;
  82. var sgwulnat = s.taboption('smartgw', form.Flag, 'SmartGatewayUplinkNAT', _('Uplink uses NAT'), _('If this Node uses NAT for connections to the internet. ' + 'Default is "yes".'));
  83. sgwulnat.depends('SmartGatewayUplink', 'ipv4');
  84. sgwulnat.depends('SmartGatewayUplink', 'both');
  85. sgwulnat.default = 'yes';
  86. sgwulnat.enabled = 'yes';
  87. sgwulnat.disabled = 'no';
  88. sgwnat.optional = true;
  89. sgwnat.rmempty = true;
  90. 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".'));
  91. sgwspeed.depends('SmartGatewayUplink', 'ipv4');
  92. sgwspeed.depends('SmartGatewayUplink', 'ipv6');
  93. sgwspeed.depends('SmartGatewayUplink', 'both');
  94. sgwspeed.optional = true;
  95. sgwspeed.rmempty = true;
  96. var sgwprefix = s.taboption(
  97. 'smartgw',
  98. form.Value,
  99. 'SmartGatewayPrefix',
  100. _('IPv6-Prefix of the uplink'),
  101. _(
  102. 'This can be used ' +
  103. "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 " +
  104. 'use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. ' +
  105. 'Default is "::/0" (no prefix).'
  106. )
  107. );
  108. sgwprefix.depends('SmartGatewayUplink', 'ipv6');
  109. sgwprefix.depends('SmartGatewayUplink', 'both');
  110. sgwprefix.optional = true;
  111. sgwprefix.rmempty = true;
  112. });
  113. s.tab('advanced', _('Advanced Settings'));
  114. 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.'));
  115. ipv.value('4', 'IPv4');
  116. ipv.value('6and4', '6and4');
  117. var poll = s.taboption('advanced', form.Value, 'Pollrate', _('Pollrate'), _('Polling rate for OLSR sockets in seconds. Default is 0.05.'));
  118. poll.optional = true;
  119. poll.datatype = 'ufloat';
  120. poll.placeholder = '0.05';
  121. 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".'));
  122. nicc.optional = true;
  123. nicc.datatype = 'ufloat';
  124. nicc.placeholder = '2.5';
  125. var tos = s.taboption('advanced', form.Value, 'TosValue', _('TOS value'), _('Type of service value for the IP header of control traffic. Default is "16".'));
  126. tos.optional = true;
  127. tos.datatype = 'uinteger';
  128. tos.placeholder = '16';
  129. var fib = s.taboption(
  130. 'general',
  131. form.ListValue,
  132. 'FIBMetric',
  133. _('FIB metric'),
  134. _(
  135. 'FIBMetric controls the metric value of the host-routes OLSRd sets. ' +
  136. '"flat" means that the metric value is always 2. This is the preferred value ' +
  137. 'because it helps the Linux kernel routing to clean up older routes. ' +
  138. '"correct" uses the hopcount as the metric value. ' +
  139. '"approx" uses the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. ' +
  140. 'Default is "flat".'
  141. )
  142. );
  143. fib.value('flat');
  144. fib.value('correct');
  145. fib.value('approx');
  146. var lql = s.taboption(
  147. 'lquality',
  148. form.ListValue,
  149. 'LinkQualityLevel',
  150. _('LQ level'),
  151. _('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"')
  152. );
  153. lql.value('2');
  154. lql.value('0');
  155. var lqage = s.taboption(
  156. 'lquality',
  157. form.Value,
  158. 'LinkQualityAging',
  159. _('LQ aging'),
  160. _('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)')
  161. );
  162. lqage.optional = true;
  163. lqage.depends('LinkQualityLevel', '2');
  164. var lqa = s.taboption(
  165. 'lquality',
  166. form.ListValue,
  167. 'LinkQualityAlgorithm',
  168. _('LQ algorithm'),
  169. _(
  170. 'Link quality algorithm (only for lq level 2).<br />' +
  171. '<b>etx_float</b>: floating point ETX with exponential aging<br />' +
  172. '<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />' +
  173. '<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />' +
  174. '<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />' +
  175. 'Defaults to "etx_ff"'
  176. )
  177. );
  178. lqa.optional = true;
  179. lqa.value('etx_ff');
  180. lqa.value('etx_fpm');
  181. lqa.value('etx_float');
  182. lqa.value('etx_ffeth');
  183. lqa.depends('LinkQualityLevel', '2');
  184. lqa.optional = true;
  185. var lqfish = s.taboption('lquality', form.Flag, 'LinkQualityFishEye', _('LQ fisheye'), _('Fisheye mechanism for TCs (checked means on). Default is "on"'));
  186. lqfish.default = '1';
  187. lqfish.optional = true;
  188. var hyst = s.taboption(
  189. 'lquality',
  190. form.Flag,
  191. 'UseHysteresis',
  192. _('Use hysteresis'),
  193. _('Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing ' + 'but delays neighbor registration. Defaults is "yes"')
  194. );
  195. hyst.default = 'yes';
  196. hyst.enabled = 'yes';
  197. hyst.disabled = 'no';
  198. hyst.depends('LinkQualityLevel', '0');
  199. hyst.optional = true;
  200. hyst.rmempty = true;
  201. 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.'));
  202. port.optional = true;
  203. port.default = '698';
  204. port.rmempty = true;
  205. var mainip = s.taboption(
  206. 'general',
  207. form.Value,
  208. 'MainIp',
  209. _('Main IP'),
  210. _('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.')
  211. );
  212. mainip.optional = true;
  213. mainip.rmempty = true;
  214. mainip.datatype = 'ipaddr';
  215. mainip.placeholder = '0.0.0.0';
  216. 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".'));
  217. for (let i = 0; i < 8; i++) {
  218. willingness.value(i);
  219. }
  220. willingness.optional = true;
  221. willingness.default = '3';
  222. var natthr = s.taboption(
  223. 'advanced',
  224. form.Value,
  225. 'NatThreshold',
  226. _('NAT threshold'),
  227. _(
  228. 'If the route to the current gateway is to be changed, the ETX value of this gateway is ' +
  229. 'multiplied with this value before it is compared to the new one. ' +
  230. 'The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />' +
  231. '<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />' +
  232. 'Defaults to "1.0".'
  233. )
  234. );
  235. for (let i = 1; i >= 0.1; i -= 0.1) {
  236. natthr.value(i);
  237. }
  238. natthr.depends('LinkQualityAlgorithm', 'etx_ff');
  239. natthr.depends('LinkQualityAlgorithm', 'etx_float');
  240. natthr.depends('LinkQualityAlgorithm', 'etx_fpm');
  241. natthr.default = '1.0';
  242. natthr.optional = true;
  243. natthr.write = function (section_id, value) {
  244. let n = parseFloat(value).toFixed(1);
  245. if (!isNaN(n)) {
  246. uci.set('olsrd', section_id, 'NatThreshold', n );
  247. }
  248. };
  249. var i = m.section(form.TypedSection, 'InterfaceDefaults', _('Interfaces Defaults'));
  250. i.anonymous = true;
  251. i.addremove = false;
  252. i.tab('general', _('General Settings'));
  253. i.tab('addrs', _('IP Addresses'));
  254. i.tab('timing', _('Timing and Validity'));
  255. 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".'));
  256. mode.value('mesh');
  257. mode.value('ether');
  258. mode.optional = true;
  259. mode.rmempty = true;
  260. var weight = i.taboption(
  261. 'general',
  262. form.Value,
  263. 'Weight',
  264. _('Weight'),
  265. _(
  266. 'When multiple links exist between hosts the weight of interface is used to determine the link to use. ' +
  267. 'Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, ' +
  268. 'but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />' +
  269. '<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. ' +
  270. 'For any other value of LinkQualityLevel, the interface ETX value is used instead.'
  271. )
  272. );
  273. weight.optional = true;
  274. weight.datatype = 'uinteger';
  275. weight.placeholder = '0';
  276. var lqmult = i.taboption(
  277. 'general',
  278. form.DynamicList,
  279. 'LinkQualityMult',
  280. _('LinkQuality Multiplicator'),
  281. _(
  282. 'Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. ' +
  283. 'It is only used when LQ-Level is greater than 0. Examples:<br />' +
  284. 'reduce LQ to 192.168.0.1 by half: 192.168.0.1 0.5<br />' +
  285. 'reduce LQ to all nodes on this interface by 20%: default 0.8'
  286. )
  287. );
  288. lqmult.optional = true;
  289. lqmult.rmempty = true;
  290. lqmult.cast = 'table';
  291. lqmult.placeholder = 'default 1.0';
  292. lqmult.validate = function (section_id) {
  293. for (var i = 0; i < lqmult.formvalue(section_id).length; i++) {
  294. var v = lqmult.formvalue(section_id)[i];
  295. if (v !== '') {
  296. var val = v.split(' ');
  297. var host = val[0];
  298. var mult = val[1];
  299. if (!host || !mult) {
  300. return [null, "LQMult requires two values (IP address or 'default' and multiplicator) separated by space."];
  301. }
  302. 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') {
  303. return [null, "Can only be a valid IPv4 or IPv6 address or 'default'"];
  304. }
  305. if (isNaN(mult) || mult > 1 || mult < 0.01) {
  306. return [null, 'Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.'];
  307. }
  308. if (!/^[0-1]\.\d+$/.test(mult)) {
  309. return [null, 'Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.'];
  310. }
  311. }
  312. }
  313. return true;
  314. };
  315. var ip4b = i.taboption(
  316. 'addrs',
  317. form.Value,
  318. 'Ip4Broadcast',
  319. _('IPv4 broadcast'),
  320. _('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.')
  321. );
  322. ip4b.optional = true;
  323. ip4b.datatype = 'ip4addr';
  324. ip4b.placeholder = '0.0.0.0';
  325. var ip6m = i.taboption('addrs', form.Value, 'IPv6Multicast', _('IPv6 multicast'), _('IPv6 multicast address. Default is "FF02::6D", the manet-router linklocal multicast.'));
  326. ip6m.optional = true;
  327. ip6m.datatype = 'ip6addr';
  328. ip6m.placeholder = 'FF02::6D';
  329. 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.'));
  330. ip4s.optional = true;
  331. ip4s.datatype = 'ip4addr';
  332. ip4s.placeholder = '0.0.0.0';
  333. var ip6s = i.taboption(
  334. 'addrs',
  335. form.Value,
  336. 'IPv6Src',
  337. _('IPv6 source'),
  338. _('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.')
  339. );
  340. ip6s.optional = true;
  341. ip6s.datatype = 'ip6addr';
  342. ip6s.placeholder = '0::/0';
  343. var hi = i.taboption('timing', form.Value, 'HelloInterval', _('Hello interval'));
  344. hi.optional = true;
  345. hi.datatype = 'ufloat';
  346. hi.placeholder = '5.0';
  347. hi.write = function (section_id, value) {
  348. let n = parseFloat(value).toFixed(1);
  349. if (!isNaN(n)) {
  350. uci.set('olsrd', section_id, 'HelloInterval', n);
  351. }
  352. };
  353. var hv = i.taboption('timing', form.Value, 'HelloValidityTime', _('Hello validity time'));
  354. hv.optional = true;
  355. hv.datatype = 'ufloat';
  356. hv.placeholder = '40.0';
  357. hv.write = function (section_id, value) {
  358. let n = parseFloat(value).toFixed(1);
  359. if (!isNaN(n)) {
  360. uci.set('olsrd', section_id, 'HelloValidityTime', n);
  361. }
  362. };
  363. var ti = i.taboption('timing', form.Value, 'TcInterval', _('TC interval'));
  364. ti.optional = true;
  365. ti.datatype = 'ufloat';
  366. ti.placeholder = '2.0';
  367. ti.write = function (section_id, value) {
  368. let n = parseFloat(value).toFixed(1);
  369. if (!isNaN(n)) {
  370. uci.set('olsrd', section_id, 'TcInterval', n);
  371. }
  372. };
  373. var tv = i.taboption('timing', form.Value, 'TcValidityTime', _('TC validity time'));
  374. tv.optional = true;
  375. tv.datatype = 'ufloat';
  376. tv.placeholder = '256.0';
  377. tv.write = function (section_id, value) {
  378. let n = parseFloat(value).toFixed(1);
  379. if (!isNaN(n)) {
  380. uci.set('olsrd', section_id, 'TcValidityTime', n);
  381. }
  382. };
  383. var mi = i.taboption('timing', form.Value, 'MidInterval', _('MID interval'));
  384. mi.optional = true;
  385. mi.datatype = 'ufloat';
  386. mi.placeholder = '18.0';
  387. mi.write = function (section_id, value) {
  388. let n = parseFloat(value).toFixed(1);
  389. if (!isNaN(n)) {
  390. uci.set('olsrd', section_id, 'MidInterval', n);
  391. }
  392. };
  393. var mv = i.taboption('timing', form.Value, 'MidValidityTime', _('MID validity time'));
  394. mv.optional = true;
  395. mv.datatype = 'ufloat';
  396. mv.placeholder = '324.0';
  397. mv.write = function (section_id, value) {
  398. let n = parseFloat(value).toFixed(1);
  399. if (!isNaN(n)) {
  400. uci.set('olsrd', section_id, 'MidValidityTime', n);
  401. }
  402. };
  403. var ai = i.taboption('timing', form.Value, 'HnaInterval', _('HNA interval'));
  404. ai.optional = true;
  405. ai.datatype = 'ufloat';
  406. ai.placeholder = '18.0';
  407. ai.write = function (section_id, value) {
  408. let n = parseFloat(value).toFixed(1);
  409. if (!isNaN(n)) {
  410. uci.set('olsrd', section_id, 'HnaInterval', n);
  411. }
  412. };
  413. var av = i.taboption('timing', form.Value, 'HnaValidityTime', _('HNA validity time'));
  414. av.optional = true;
  415. av.datatype = 'ufloat';
  416. av.placeholder = '108.0';
  417. av.write = function (section_id, value) {
  418. let n = parseFloat(value).toFixed(1);
  419. if (!isNaN(n)) {
  420. uci.set('olsrd', section_id, 'HnaValidityTime', n);
  421. }
  422. };
  423. var ifs = m.section(form.TableSection, 'Interface', _('Interfaces'));
  424. ifs.addremove = true;
  425. ifs.anonymous = true;
  426. ifs.extedit = function (eve) {
  427. var editButton = eve.target;
  428. var sid;
  429. var row = editButton.closest('.cbi-section-table-row');
  430. if (row) {
  431. sid = row.getAttribute('data-sid');
  432. console.log(sid);
  433. }
  434. window.location.href = `olsrd/iface/${sid}`;
  435. };
  436. ifs.template = 'cbi/tblsection';
  437. ifs.handleAdd = function (ev) {
  438. var sid = uci.add('olsrd', 'Interface');
  439. uci
  440. .save()
  441. .then(function () {
  442. return uci.changes();
  443. })
  444. .then(function (res) {
  445. console.log(res);
  446. var sid = null;
  447. if (res.olsrd && Array.isArray(res.olsrd)) {
  448. res.olsrd.forEach(function (item) {
  449. if (item.length >= 3 && item[0] === 'add' && item[2] === 'Interface') {
  450. sid = item[1];
  451. }
  452. });
  453. }
  454. if (sid) {
  455. console.log(sid);
  456. }
  457. window.location.href = `olsrd/iface/${sid}`;
  458. });
  459. };
  460. var ign = ifs.option(form.Flag, 'ignore', _('Enable'));
  461. ign.enabled = '0';
  462. ign.disabled = '1';
  463. ign.rmempty = false;
  464. ign.cfgvalue = function (section_id) {
  465. return uci.get('olsrd', section_id, 'ignore') || '0';
  466. };
  467. var network = ifs.option(form.DummyValue, 'interface', _('Network'));
  468. network.template = 'cbi/network_netinfo';
  469. var mode = ifs.option(form.DummyValue, 'Mode', _('Mode'));
  470. mode.cfgvalue = function (section_id) {
  471. return uci.get('olsrd', section_id, 'Mode') || uci.get_first('olsrd', 'InterfaceDefaults', 'Mode');
  472. };
  473. var hello = ifs.option(form.DummyValue, '_hello', _('Hello'));
  474. hello.cfgvalue = function (section_id) {
  475. var i = uci.get('olsrd', section_id, 'HelloInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'HelloInterval');
  476. var v = uci.get('olsrd', section_id, 'HelloValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'HelloValidityTime');
  477. return `${i}s / ${v}s`;
  478. };
  479. var tc = ifs.option(form.DummyValue, '_tc', _('TC'));
  480. tc.cfgvalue = function (section_id) {
  481. var i = uci.get('olsrd', section_id, 'TcInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'TcInterval');
  482. var v = uci.get('olsrd', section_id, 'TcValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'TcValidityTime');
  483. return `${i}s / ${v}s`;
  484. };
  485. var mid = ifs.option(form.DummyValue, '_mid', _('MID'));
  486. mid.cfgvalue = function (section_id) {
  487. var i = uci.get('olsrd', section_id, 'MidInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'MidInterval');
  488. var v = uci.get('olsrd', section_id, 'MidValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'MidValidityTime');
  489. return `${i}s / ${v}s`;
  490. };
  491. var hna = ifs.option(form.DummyValue, '_hna', _('HNA'));
  492. hna.cfgvalue = function (section_id) {
  493. var i = uci.get('olsrd', section_id, 'HnaInterval') || uci.get_first('olsrd', 'InterfaceDefaults', 'HnaInterval');
  494. var v = uci.get('olsrd', section_id, 'HnaValidityTime') || uci.get_first('olsrd', 'InterfaceDefaults', 'HnaValidityTime');
  495. return `${i}s / ${v}s`;
  496. };
  497. return m.render();
  498. },
  499. });