olsrd6.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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('olsrd6').then(() => {
  15. var hasDefaults = false;
  16. uci.sections('olsrd6', 'InterfaceDefaults', function (s) {
  17. hasDefaults = true;
  18. return false;
  19. });
  20. if (!hasDefaults) {
  21. uci.add('olsrd6', 'InterfaceDefaults');
  22. }
  23. })]);
  24. },
  25. render: function () {
  26. let m, s, o;
  27. var has_ipip;
  28. m = new form.Map(
  29. 'olsrd6',
  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, 'olsrd6', _('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('olsrd6', 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 HNA6 ::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 poll = s.taboption('advanced', form.Value, 'Pollrate', _('Pollrate'), _('Polling rate for OLSR sockets in seconds. Default is 0.05.'));
  115. poll.optional = true;
  116. poll.datatype = 'ufloat';
  117. poll.placeholder = '0.05';
  118. 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".'));
  119. nicc.optional = true;
  120. nicc.datatype = 'ufloat';
  121. nicc.placeholder = '2.5';
  122. var tos = s.taboption('advanced', form.Value, 'TosValue', _('TOS value'), _('Type of service value for the IP header of control traffic. Default is "16".'));
  123. tos.optional = true;
  124. tos.datatype = 'uinteger';
  125. tos.placeholder = '16';
  126. var fib = s.taboption(
  127. 'general',
  128. form.ListValue,
  129. 'FIBMetric',
  130. _('FIB metric'),
  131. _(
  132. 'FIBMetric controls the metric value of the host-routes OLSRd sets. ' +
  133. '"flat" means that the metric value is always 2. This is the preferred value ' +
  134. 'because it helps the Linux kernel routing to clean up older routes. ' +
  135. '"correct" uses the hopcount as the metric value. ' +
  136. '"approx" uses the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. ' +
  137. 'Default is "flat".'
  138. )
  139. );
  140. fib.value('flat');
  141. fib.value('correct');
  142. fib.value('approx');
  143. var lql = s.taboption(
  144. 'lquality',
  145. form.ListValue,
  146. 'LinkQualityLevel',
  147. _('LQ level'),
  148. _('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"')
  149. );
  150. lql.value('2');
  151. lql.value('0');
  152. var lqage = s.taboption(
  153. 'lquality',
  154. form.Value,
  155. 'LinkQualityAging',
  156. _('LQ aging'),
  157. _('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)')
  158. );
  159. lqage.optional = true;
  160. lqage.depends('LinkQualityLevel', '2');
  161. var lqa = s.taboption(
  162. 'lquality',
  163. form.ListValue,
  164. 'LinkQualityAlgorithm',
  165. _('LQ algorithm'),
  166. _(
  167. 'Link quality algorithm (only for lq level 2).<br />' +
  168. '<b>etx_float</b>: floating point ETX with exponential aging<br />' +
  169. '<b>etx_fpm</b> : same as etx_float, but with integer arithmetic<br />' +
  170. '<b>etx_ff</b> : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />' +
  171. '<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />' +
  172. 'Defaults to "etx_ff"'
  173. )
  174. );
  175. lqa.optional = true;
  176. lqa.value('etx_ff');
  177. lqa.value('etx_fpm');
  178. lqa.value('etx_float');
  179. lqa.value('etx_ffeth');
  180. lqa.depends('LinkQualityLevel', '2');
  181. lqa.optional = true;
  182. var lqfish = s.taboption('lquality', form.Flag, 'LinkQualityFishEye', _('LQ fisheye'), _('Fisheye mechanism for TCs (checked means on). Default is "on"'));
  183. lqfish.default = '1';
  184. lqfish.optional = true;
  185. var hyst = s.taboption(
  186. 'lquality',
  187. form.Flag,
  188. 'UseHysteresis',
  189. _('Use hysteresis'),
  190. _('Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing ' + 'but delays neighbor registration. Defaults is "yes"')
  191. );
  192. hyst.default = 'yes';
  193. hyst.enabled = 'yes';
  194. hyst.disabled = 'no';
  195. hyst.depends('LinkQualityLevel', '0');
  196. hyst.optional = true;
  197. hyst.rmempty = true;
  198. 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.'));
  199. port.optional = true;
  200. port.default = '698';
  201. port.rmempty = true;
  202. var mainip = s.taboption(
  203. 'general',
  204. form.Value,
  205. 'MainIp',
  206. _('Main IP'),
  207. _('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.')
  208. );
  209. mainip.optional = true;
  210. mainip.rmempty = true;
  211. mainip.datatype = 'ipaddr';
  212. mainip.placeholder = '::';
  213. 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".'));
  214. for (let i = 0; i < 8; i++) {
  215. willingness.value(i);
  216. }
  217. willingness.optional = true;
  218. willingness.default = '3';
  219. var natthr = s.taboption(
  220. 'advanced',
  221. form.Value,
  222. 'NatThreshold',
  223. _('NAT threshold'),
  224. _(
  225. 'If the route to the current gateway is to be changed, the ETX value of this gateway is ' +
  226. 'multiplied with this value before it is compared to the new one. ' +
  227. 'The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />' +
  228. '<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />' +
  229. 'Defaults to "1.0".'
  230. )
  231. );
  232. for (let i = 1; i >= 0.1; i -= 0.1) {
  233. natthr.value(i);
  234. }
  235. natthr.depends('LinkQualityAlgorithm', 'etx_ff');
  236. natthr.depends('LinkQualityAlgorithm', 'etx_float');
  237. natthr.depends('LinkQualityAlgorithm', 'etx_fpm');
  238. natthr.default = '1.0';
  239. natthr.optional = true;
  240. natthr.write = function (section_id, value) {
  241. let n = parseFloat(value).toFixed(1);
  242. if (!isNaN(n)) {
  243. uci.set('olsrd6', section_id, 'NatThreshold', n);
  244. }
  245. };
  246. var i = m.section(form.TypedSection, 'InterfaceDefaults', _('Interfaces Defaults'));
  247. i.anonymous = true;
  248. i.addremove = false;
  249. i.tab('general', _('General Settings'));
  250. i.tab('addrs', _('IP Addresses'));
  251. i.tab('timing', _('Timing and Validity'));
  252. 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".'));
  253. mode.value('mesh');
  254. mode.value('ether');
  255. mode.optional = true;
  256. mode.rmempty = true;
  257. var weight = i.taboption(
  258. 'general',
  259. form.Value,
  260. 'Weight',
  261. _('Weight'),
  262. _(
  263. 'When multiple links exist between hosts the weight of interface is used to determine the link to use. ' +
  264. 'Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, ' +
  265. 'but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />' +
  266. '<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. ' +
  267. 'For any other value of LinkQualityLevel, the interface ETX value is used instead.'
  268. )
  269. );
  270. weight.optional = true;
  271. weight.datatype = 'uinteger';
  272. weight.placeholder = '0';
  273. var lqmult = i.taboption(
  274. 'general',
  275. form.DynamicList,
  276. 'LinkQualityMult',
  277. _('LinkQuality Multiplicator'),
  278. _(
  279. 'Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. ' +
  280. 'It is only used when LQ-Level is greater than 0. Examples:<br />' +
  281. 'reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />' +
  282. 'reduce LQ to all nodes on this interface by 20%: default 0.8'
  283. )
  284. );
  285. lqmult.optional = true;
  286. lqmult.rmempty = true;
  287. lqmult.cast = 'table';
  288. lqmult.placeholder = 'default 1.0';
  289. lqmult.validate = function (section_id) {
  290. for (var i = 0; i < lqmult.formvalue(section_id).length; i++) {
  291. var v = lqmult.formvalue(section_id)[i];
  292. if (v !== '') {
  293. var val = v.split(' ');
  294. var host = val[0];
  295. var mult = val[1];
  296. if (!host || !mult) {
  297. return [null, "LQMult requires two values (IP address or 'default' and multiplicator) separated by space."];
  298. }
  299. if (!/^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/.test(host) && host !== 'default') {
  300. return [null, "Can only be a valid IPv6 address or 'default'"];
  301. }
  302. if (isNaN(mult) || mult > 1 || mult < 0.01) {
  303. return [null, 'Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.'];
  304. }
  305. if (!/^[0-1]\.\d+$/.test(mult)) {
  306. return [null, 'Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.'];
  307. }
  308. }
  309. }
  310. return true;
  311. };
  312. var ip6m = i.taboption('addrs', form.Value, 'IPv6Multicast', _('IPv6 multicast'), _('IPv6 multicast address. Default is "FF02::6D", the manet-router linklocal multicast.'));
  313. ip6m.optional = true;
  314. ip6m.datatype = 'ip6addr';
  315. ip6m.placeholder = 'FF02::6D';
  316. var ip6s = i.taboption(
  317. 'addrs',
  318. form.Value,
  319. 'IPv6Src',
  320. _('IPv6 source'),
  321. _('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.')
  322. );
  323. ip6s.optional = true;
  324. ip6s.datatype = 'ip6addr';
  325. ip6s.placeholder = '0::/0';
  326. var hi = i.taboption('timing', form.Value, 'HelloInterval', _('Hello interval'));
  327. hi.optional = true;
  328. hi.datatype = 'ufloat';
  329. hi.placeholder = '5.0';
  330. hi.write = function (section_id, value) {
  331. let n = parseFloat(value).toFixed(1);
  332. if (!isNaN(n)) {
  333. uci.set('olsrd6', section_id, 'HelloInterval', n);
  334. }
  335. };
  336. var hv = i.taboption('timing', form.Value, 'HelloValidityTime', _('Hello validity time'));
  337. hv.optional = true;
  338. hv.datatype = 'ufloat';
  339. hv.placeholder = '40.0';
  340. hv.write = function (section_id, value) {
  341. let n = parseFloat(value).toFixed(1);
  342. if (!isNaN(n)) {
  343. uci.set('olsrd6', section_id, 'HelloValidityTime', n);
  344. }
  345. };
  346. var ti = i.taboption('timing', form.Value, 'TcInterval', _('TC interval'));
  347. ti.optional = true;
  348. ti.datatype = 'ufloat';
  349. ti.placeholder = '2.0';
  350. ti.write = function (section_id, value) {
  351. let n = parseFloat(value).toFixed(1);
  352. if (!isNaN(n)) {
  353. uci.set('olsrd6', section_id, 'TcInterval', n);
  354. }
  355. };
  356. var tv = i.taboption('timing', form.Value, 'TcValidityTime', _('TC validity time'));
  357. tv.optional = true;
  358. tv.datatype = 'ufloat';
  359. tv.placeholder = '256.0';
  360. tv.write = function (section_id, value) {
  361. let n = parseFloat(value).toFixed(1);
  362. if (!isNaN(n)) {
  363. uci.set('olsrd6', section_id, 'TcValidityTime', n);
  364. }
  365. };
  366. var mi = i.taboption('timing', form.Value, 'MidInterval', _('MID interval'));
  367. mi.optional = true;
  368. mi.datatype = 'ufloat';
  369. mi.placeholder = '18.0';
  370. mi.write = function (section_id, value) {
  371. let n = parseFloat(value).toFixed(1);
  372. if (!isNaN(n)) {
  373. uci.set('olsrd6', section_id, 'MidInterval', n);
  374. }
  375. };
  376. var mv = i.taboption('timing', form.Value, 'MidValidityTime', _('MID validity time'));
  377. mv.optional = true;
  378. mv.datatype = 'ufloat';
  379. mv.placeholder = '324.0';
  380. mv.write = function (section_id, value) {
  381. let n = parseFloat(value).toFixed(1);
  382. if (!isNaN(n)) {
  383. uci.set('olsrd6', section_id, 'MidValidityTime', n);
  384. }
  385. };
  386. var ai = i.taboption('timing', form.Value, 'HnaInterval', _('HNA interval'));
  387. ai.optional = true;
  388. ai.datatype = 'ufloat';
  389. ai.placeholder = '18.0';
  390. ai.write = function (section_id, value) {
  391. let n = parseFloat(value).toFixed(1);
  392. if (!isNaN(n)) {
  393. uci.set('olsrd6', section_id, 'HnaInterval', n);
  394. }
  395. };
  396. var av = i.taboption('timing', form.Value, 'HnaValidityTime', _('HNA validity time'));
  397. av.optional = true;
  398. av.datatype = 'ufloat';
  399. av.placeholder = '108.0';
  400. av.write = function (section_id, value) {
  401. let n = parseFloat(value).toFixed(1);
  402. if (!isNaN(n)) {
  403. uci.set('olsrd6', section_id, 'HnaValidityTime', n);
  404. }
  405. };
  406. var ifs = m.section(form.TableSection, 'Interface', _('Interfaces'));
  407. ifs.addremove = true;
  408. ifs.anonymous = true;
  409. ifs.extedit = function (eve) {
  410. var editButton = eve.target;
  411. var sid;
  412. var row = editButton.closest('.cbi-section-table-row');
  413. if (row) {
  414. sid = row.getAttribute('data-sid');
  415. console.log(sid);
  416. }
  417. window.location.href = `olsrd6/iface/${sid}`;
  418. };
  419. ifs.template = 'cbi/tblsection';
  420. ifs.handleAdd = function (ev) {
  421. var sid = uci.add('olsrd6', 'Interface');
  422. uci
  423. .save()
  424. .then(function () {
  425. return uci.changes();
  426. })
  427. .then(function (res) {
  428. console.log(res);
  429. var sid = null;
  430. if (res.olsrd6 && Array.isArray(res.olsrd6)) {
  431. res.olsrd6.forEach(function (item) {
  432. if (item.length >= 3 && item[0] === 'add' && item[2] === 'Interface') {
  433. sid = item[1];
  434. }
  435. });
  436. }
  437. if (sid) {
  438. console.log(sid);
  439. }
  440. window.location.href = `olsrd6/iface/${sid}`;
  441. });
  442. };
  443. var ign = ifs.option(form.Flag, 'ignore', _('Enable'));
  444. ign.enabled = '0';
  445. ign.disabled = '1';
  446. ign.rmempty = false;
  447. ign.cfgvalue = function (section_id) {
  448. return uci.get('olsrd6', section_id, 'ignore') || '0';
  449. };
  450. var network = ifs.option(form.DummyValue, 'interface', _('Network'));
  451. network.template = 'cbi/network_netinfo';
  452. var mode = ifs.option(form.DummyValue, 'Mode', _('Mode'));
  453. mode.cfgvalue = function (section_id) {
  454. return uci.get('olsrd6', section_id, 'Mode') || uci.get_first('olsrd6', 'InterfaceDefaults', 'Mode');
  455. };
  456. var hello = ifs.option(form.DummyValue, '_hello', _('Hello'));
  457. hello.cfgvalue = function (section_id) {
  458. var i = uci.get('olsrd6', section_id, 'HelloInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HelloInterval');
  459. var v = uci.get('olsrd6', section_id, 'HelloValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HelloValidityTime');
  460. return `${i}s / ${v}s`;
  461. };
  462. var tc = ifs.option(form.DummyValue, '_tc', _('TC'));
  463. tc.cfgvalue = function (section_id) {
  464. var i = uci.get('olsrd6', section_id, 'TcInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'TcInterval');
  465. var v = uci.get('olsrd6', section_id, 'TcValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'TcValidityTime');
  466. return `${i}s / ${v}s`;
  467. };
  468. var mid = ifs.option(form.DummyValue, '_mid', _('MID'));
  469. mid.cfgvalue = function (section_id) {
  470. var i = uci.get('olsrd6', section_id, 'MidInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'MidInterval');
  471. var v = uci.get('olsrd6', section_id, 'MidValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'MidValidityTime');
  472. return `${i}s / ${v}s`;
  473. };
  474. var hna = ifs.option(form.DummyValue, '_hna', _('HNA'));
  475. hna.cfgvalue = function (section_id) {
  476. var i = uci.get('olsrd6', section_id, 'HnaInterval') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HnaInterval');
  477. var v = uci.get('olsrd6', section_id, 'HnaValidityTime') || uci.get_first('olsrd6', 'InterfaceDefaults', 'HnaValidityTime');
  478. return `${i}s / ${v}s`;
  479. };
  480. return m.render();
  481. },
  482. });