7 CONNECT_FAILED: _('Connection attempt failed'),
8 INVALID_ADDRESS: _('IP address in invalid'),
9 INVALID_GATEWAY: _('Gateway address is invalid'),
10 INVALID_LOCAL_ADDRESS: _('Local IP address is invalid'),
11 MISSING_ADDRESS: _('IP address is missing'),
12 MISSING_PEER_ADDRESS: _('Peer address is missing'),
13 NO_DEVICE: _('Network device is not present'),
14 NO_IFACE: _('Unable to determine device name'),
15 NO_IFNAME: _('Unable to determine device name'),
16 NO_WAN_ADDRESS: _('Unable to determine external IP address'),
17 NO_WAN_LINK: _('Unable to determine upstream interface'),
18 PEER_RESOLVE_FAIL: _('Unable to resolve peer host name'),
19 PIN_FAILED: _('PIN code rejected')
22 var iface_patterns_ignore = [
38 var iface_patterns_wireless = [
45 var iface_patterns_virtual = [ ];
47 var callNetworkWirelessStatus = rpc.declare({
48 object: 'network.wireless',
52 var callLuciNetdevs = rpc.declare({
57 var callLuciIfaddrs = rpc.declare({
60 expect: { result: [] }
63 var callLuciBoardjson = rpc.declare({
68 var callIwinfoInfo = rpc.declare({
74 var callNetworkInterfaceStatus = rpc.declare({
75 object: 'network.interface',
77 expect: { 'interface': [] }
80 var callNetworkDeviceStatus = rpc.declare({
81 object: 'network.device',
90 function getWifiState() {
91 if (_cache.wifi == null)
92 return callNetworkWirelessStatus().then(function(state) {
93 if (!L.isObject(state))
95 return (_cache.wifi = state);
97 return (_cache.wifi = {});
100 return Promise.resolve(_cache.wifi);
103 function getInterfaceState() {
104 if (_cache.interfacedump == null)
105 return callNetworkInterfaceStatus().then(function(state) {
106 if (!Array.isArray(state))
108 return (_cache.interfacedump = state);
109 }).catch(function() {
110 return (_cache.interfacedump = []);
113 return Promise.resolve(_cache.interfacedump);
116 function getDeviceState() {
117 if (_cache.devicedump == null)
118 return callNetworkDeviceStatus().then(function(state) {
119 if (!L.isObject(state))
121 return (_cache.devicedump = state);
122 }).catch(function() {
123 return (_cache.devicedump = {});
126 return Promise.resolve(_cache.devicedump);
129 function getIfaddrState() {
130 if (_cache.ifaddrs == null)
131 return callLuciIfaddrs().then(function(addrs) {
132 if (!Array.isArray(addrs))
134 return (_cache.ifaddrs = addrs);
135 }).catch(function() {
136 return (_cache.ifaddrs = []);
139 return Promise.resolve(_cache.ifaddrs);
142 function getNetdevState() {
143 if (_cache.devices == null)
144 return callLuciNetdevs().then(function(state) {
145 if (!L.isObject(state))
147 return (_cache.devices = state);
148 }).catch(function() {
149 return (_cache.devices = {});
152 return Promise.resolve(_cache.devices);
155 function getBoardState() {
156 if (_cache.board == null)
157 return callLuciBoardjson().then(function(state) {
158 if (!L.isObject(state))
160 return (_cache.board = state);
161 }).catch(function() {
162 return (_cache.board = {});
165 return Promise.resolve(_cache.board);
168 function getWifiStateBySid(sid) {
169 var s = uci.get('wireless', sid);
171 if (s != null && s['.type'] == 'wifi-iface') {
172 for (var radioname in _cache.wifi) {
173 for (var i = 0; i < _cache.wifi[radioname].interfaces.length; i++) {
174 var netstate = _cache.wifi[radioname].interfaces[i];
176 if (typeof(netstate.section) != 'string')
179 var s2 = uci.get('wireless', netstate.section);
181 if (s2 != null && s['.type'] == s2['.type'] && s['.name'] == s2['.name'])
182 return [ radioname, _cache.wifi[radioname], netstate ];
190 function getWifiStateByIfname(ifname) {
191 for (var radioname in _cache.wifi) {
192 for (var i = 0; i < _cache.wifi[radioname].interfaces.length; i++) {
193 var netstate = _cache.wifi[radioname].interfaces[i];
195 if (typeof(netstate.ifname) != 'string')
198 if (netstate.ifname == ifname)
199 return [ radioname, _cache.wifi[radioname], netstate ];
206 function isWifiIfname(ifname) {
207 for (var i = 0; i < iface_patterns_wireless.length; i++)
208 if (iface_patterns_wireless[i].test(ifname))
214 function getWifiIwinfoByIfname(ifname, forcePhyOnly) {
215 var tasks = [ callIwinfoInfo(ifname) ];
218 tasks.push(getNetdevState());
220 return Promise.all(tasks).then(function(info) {
221 var iwinfo = info[0],
223 phyonly = forcePhyOnly || !devstate[ifname] || (devstate[ifname].type != 1);
225 if (L.isObject(iwinfo)) {
227 delete iwinfo.bitrate;
228 delete iwinfo.quality;
229 delete iwinfo.quality_max;
233 delete iwinfo.encryption;
236 iwinfo.ifname = ifname;
240 }).catch(function() {
245 function getWifiSidByNetid(netid) {
246 var m = /^(\w+)\.network(\d+)$/.exec(netid);
248 var sections = uci.sections('wireless', 'wifi-iface');
249 for (var i = 0, n = 0; i < sections.length; i++) {
250 if (sections[i].device != m[1])
254 return sections[i]['.name'];
261 function getWifiSidByIfname(ifname) {
262 var sid = getWifiSidByNetid(ifname);
267 var res = getWifiStateByIfname(ifname);
269 if (res != null && L.isObject(res[2]) && typeof(res[2].section) == 'string')
270 return res[2].section;
275 function getWifiNetidBySid(sid) {
276 var s = uci.get('wireless', sid);
277 if (s != null && s['.type'] == 'wifi-iface') {
278 var radioname = s.device;
279 if (typeof(s.device) == 'string') {
280 var i = 0, netid = null, sections = uci.sections('wireless', 'wifi-iface');
281 for (var i = 0, n = 0; i < sections.length; i++) {
282 if (sections[i].device != s.device)
287 if (sections[i]['.name'] != s['.name'])
290 return [ '%s.network%d'.format(s.device, n), s.device ];
299 function getWifiNetidByNetname(name) {
300 var sections = uci.sections('wireless', 'wifi-iface');
301 for (var i = 0; i < sections.length; i++) {
302 if (typeof(sections[i].network) != 'string')
305 var nets = sections[i].network.split(/\s+/);
306 for (var j = 0; j < nets.length; j++) {
310 return getWifiNetidBySid(sections[i]['.name']);
317 function isVirtualIfname(ifname) {
318 for (var i = 0; i < iface_patterns_virtual.length; i++)
319 if (iface_patterns_virtual[i].test(ifname))
325 function isIgnoredIfname(ifname) {
326 for (var i = 0; i < iface_patterns_ignore.length; i++)
327 if (iface_patterns_ignore[i].test(ifname))
333 function appendValue(config, section, option, value) {
334 var values = uci.get(config, section, option),
335 isArray = Array.isArray(values),
338 if (isArray == false)
339 values = String(values || '').split(/\s+/);
341 if (values.indexOf(value) == -1) {
346 uci.set(config, section, option, isArray ? values : values.join(' '));
351 function removeValue(config, section, option, value) {
352 var values = uci.get(config, section, option),
353 isArray = Array.isArray(values),
356 if (isArray == false)
357 values = String(values || '').split(/\s+/);
359 for (var i = values.length - 1; i >= 0; i--) {
360 if (values[i] == value) {
366 if (values.length > 0)
367 uci.set(config, section, option, isArray ? values : values.join(' '));
369 uci.unset(config, section, option);
374 function prefixToMask(bits, v6) {
375 var w = v6 ? 128 : 32,
381 for (var i = 0; i < w / 16; i++) {
382 var b = Math.min(16, bits);
383 m.push((0xffff << (16 - b)) & 0xffff);
388 return String.prototype.format.apply('%x:%x:%x:%x:%x:%x:%x:%x', m).replace(/:0(?::0)+$/, '::');
390 return '%d.%d.%d.%d'.format(m[0] >>> 8, m[0] & 0xff, m[1] >>> 8, m[1] & 0xff);
393 function maskToPrefix(mask, v6) {
394 var m = v6 ? validation.parseIPv6(mask) : validation.parseIPv4(mask);
401 for (var i = 0, z = false; i < m.length; i++) {
404 while (!z && (m[i] & (v6 ? 0x8000 : 0x80))) {
405 m[i] = (m[i] << 1) & (v6 ? 0xffff : 0xff);
416 function initNetworkState() {
418 return (_state = Promise.all([
419 getInterfaceState(), getDeviceState(), getBoardState(),
420 getWifiState(), getIfaddrState(), getNetdevState(),
421 uci.load('network'), uci.load('wireless'), uci.load('luci')
422 ]).finally(function() {
423 var ifaddrs = _cache.ifaddrs,
424 devices = _cache.devices,
425 board = _cache.board,
426 s = { isTunnel: {}, isBridge: {}, isSwitch: {}, isWifi: {}, interfaces: {}, bridges: {}, switches: {} };
428 for (var i = 0, a; (a = ifaddrs[i]) != null; i++) {
429 var name = a.name.replace(/:.+$/, '');
431 if (isVirtualIfname(name))
432 s.isTunnel[name] = true;
434 if (s.isTunnel[name] || !(isIgnoredIfname(name) || isVirtualIfname(name))) {
435 s.interfaces[name] = s.interfaces[name] || {
444 if (a.family == 'packet') {
445 s.interfaces[name].flags = a.flags;
446 s.interfaces[name].stats = a.data;
447 s.interfaces[name].macaddr = a.addr;
449 else if (a.family == 'inet') {
450 s.interfaces[name].ipaddrs.push(a.addr + '/' + a.netmask);
452 else if (a.family == 'inet6') {
453 s.interfaces[name].ip6addrs.push(a.addr + '/' + a.netmask);
458 for (var devname in devices) {
459 var dev = devices[devname];
469 for (var i = 0; dev.ports && i < dev.ports.length; i++) {
470 var subdev = s.interfaces[dev.ports[i]];
475 b.ifnames.push(subdev);
479 s.bridges[devname] = b;
483 if (L.isObject(board.switch)) {
484 for (var switchname in board.switch) {
485 var layout = board.switch[switchname],
492 if (L.isObject(layout) && Array.isArray(layout.ports)) {
493 for (var i = 0, port; (port = layout.ports[i]) != null; i++) {
494 if (typeof(port) == 'object' && typeof(port.num) == 'number' &&
495 (typeof(port.role) == 'string' || typeof(port.device) == 'string')) {
498 role: port.role || 'cpu',
499 index: (port.index != null) ? port.index : port.num
502 if (port.device != null) {
503 spec.device = port.device;
504 spec.tagged = spec.need_tag;
505 netdevs[port.num] = port.device;
510 if (port.role != null)
511 nports[port.role] = (nports[port.role] || 0) + 1;
515 ports.sort(function(a, b) {
516 if (a.role != b.role)
517 return (a.role < b.role) ? -1 : 1;
519 return (a.index - b.index);
522 for (var i = 0, port; (port = ports[i]) != null; i++) {
523 if (port.role != role) {
529 port.label = 'CPU (%s)'.format(port.device);
530 else if (nports[role] > 1)
531 port.label = '%s %d'.format(role.toUpperCase(), pnum++);
533 port.label = role.toUpperCase();
539 s.switches[switchname] = {
550 return Promise.resolve(_state);
553 function ifnameOf(obj) {
554 if (obj instanceof Interface)
556 else if (obj instanceof Protocol)
558 else if (typeof(obj) == 'string')
559 return obj.replace(/:.+$/, '');
564 function networkSort(a, b) {
565 return a.getName() > b.getName();
568 function deviceSort(a, b) {
569 var typeWeigth = { wifi: 2, alias: 3 },
570 weightA = typeWeigth[a.getType()] || 1,
571 weightB = typeWeigth[b.getType()] || 1;
573 if (weightA != weightB)
574 return weightA - weightB;
576 return a.getName() > b.getName();
580 var Network, Protocol, Device, WifiDevice, WifiNetwork;
582 Network = L.Class.extend({
583 getProtocol: function(protoname, netname) {
584 var v = _protocols[protoname];
586 return v(netname || '__dummy__');
591 getProtocols: function() {
594 for (var protoname in _protocols)
595 rv.push(_protocols[protoname]('__dummy__'));
600 registerProtocol: function(protoname, methods) {
601 var proto = Protocol.extend(Object.assign({}, methods, {
602 __init__: function(name) {
611 _protocols[protoname] = proto;
616 registerPatternVirtual: function(pat) {
617 iface_patterns_virtual.push(pat);
620 registerErrorCode: function(code, message) {
621 if (typeof(code) == 'string' &&
622 typeof(message) == 'string' &&
623 proto_errors.hasOwnProperty(code)) {
624 proto_errors[code] = message;
631 addNetwork: function(name, options) {
632 return this.getNetwork(name).then(L.bind(function(existingNetwork) {
633 if (name != null && /^[a-zA-Z0-9_]+$/.test(name) && existingNetwork == null) {
634 var sid = uci.add('network', 'interface', name);
637 if (L.isObject(options))
638 for (var key in options)
639 if (options.hasOwnProperty(key))
640 uci.set('network', sid, key, options[key]);
642 return this.instantiateNetwork(sid);
645 else if (existingNetwork != null && existingNetwork.isEmpty()) {
646 if (L.isObject(options))
647 for (var key in options)
648 if (options.hasOwnProperty(key))
649 existingNetwork.set(key, options[key]);
651 return existingNetwork;
656 getNetwork: function(name) {
657 return initNetworkState().then(L.bind(function() {
658 var section = (name != null) ? uci.get('network', name) : null;
660 if (section != null && section['.type'] == 'interface') {
661 return this.instantiateNetwork(name);
663 else if (name != null) {
664 for (var i = 0; i < _cache.interfacedump.length; i++)
665 if (_cache.interfacedump[i].interface == name)
666 return this.instantiateNetwork(name, _cache.interfacedump[i].proto);
673 getNetworks: function() {
674 return initNetworkState().then(L.bind(function() {
675 var uciInterfaces = uci.sections('network', 'interface'),
678 for (var i = 0; i < uciInterfaces.length; i++)
679 networks[uciInterfaces[i]['.name']] = this.instantiateNetwork(uciInterfaces[i]['.name']);
681 for (var i = 0; i < _cache.interfacedump.length; i++)
682 if (networks[_cache.interfacedump[i].interface] == null)
683 networks[_cache.interfacedump[i].interface] =
684 this.instantiateNetwork(_cache.interfacedump[i].interface, _cache.interfacedump[i].proto);
688 for (var network in networks)
689 if (networks.hasOwnProperty(network))
690 rv.push(networks[network]);
692 rv.sort(networkSort);
698 deleteNetwork: function(name) {
699 return Promise.all([ L.require('firewall').catch(function() { return null }), initNetworkState() ]).then(function() {
700 var uciInterface = uci.get('network', name);
702 if (uciInterface != null && uciInterface['.type'] == 'interface') {
703 uci.remove('network', name);
705 uci.sections('luci', 'ifstate', function(s) {
706 if (s.interface == name)
707 uci.remove('luci', s['.name']);
710 uci.sections('network', 'alias', function(s) {
711 if (s.interface == name)
712 uci.remove('network', s['.name']);
715 uci.sections('network', 'route', function(s) {
716 if (s.interface == name)
717 uci.remove('network', s['.name']);
720 uci.sections('network', 'route6', function(s) {
721 if (s.interface == name)
722 uci.remove('network', s['.name']);
725 uci.sections('wireless', 'wifi-iface', function(s) {
726 var networks = L.toArray(s.network).filter(function(network) { return network != name });
728 if (networks.length > 0)
729 uci.set('wireless', s['.name'], 'network', networks.join(' '));
731 uci.unset('wireless', s['.name'], 'network');
735 return L.firewall.deleteNetwork(name).then(function() { return true });
744 renameNetwork: function(oldName, newName) {
745 return initNetworkState().then(function() {
746 if (newName == null || !/^[a-zA-Z0-9_]+$/.test(newName) || uci.get('network', newName) != null)
749 var oldNetwork = uci.get('network', oldName);
751 if (oldNetwork == null || oldNetwork['.type'] != 'interface')
754 var sid = uci.add('network', 'interface', newName);
756 for (var key in oldNetwork)
757 if (oldNetwork.hasOwnProperty(key) && key.charAt(0) != '.')
758 uci.set('network', sid, key, oldNetwork[key]);
760 uci.sections('luci', 'ifstate', function(s) {
761 if (s.interface == oldName)
762 uci.set('luci', s['.name'], 'interface', newName);
765 uci.sections('network', 'alias', function(s) {
766 if (s.interface == oldName)
767 uci.set('network', s['.name'], 'interface', newName);
770 uci.sections('network', 'route', function(s) {
771 if (s.interface == oldName)
772 uci.set('network', s['.name'], 'interface', newName);
775 uci.sections('network', 'route6', function(s) {
776 if (s.interface == oldName)
777 uci.set('network', s['.name'], 'interface', newName);
780 uci.sections('wireless', 'wifi-iface', function(s) {
781 var networks = L.toArray(s.network).map(function(network) { return (network == oldName ? newName : network) });
783 if (networks.length > 0)
784 uci.set('wireless', s['.name'], 'network', networks.join(' '));
787 uci.remove('network', oldName);
793 getDevice: function(name) {
794 return initNetworkState().then(L.bind(function() {
798 if (_state.interfaces.hasOwnProperty(name) || isWifiIfname(name))
799 return this.instantiateDevice(name);
801 var netid = getWifiNetidBySid(name);
803 return this.instantiateDevice(netid[0]);
809 getDevices: function() {
810 return initNetworkState().then(L.bind(function() {
813 /* find simple devices */
814 var uciInterfaces = uci.sections('network', 'interface');
815 for (var i = 0; i < uciInterfaces.length; i++) {
816 var ifnames = L.toArray(uciInterfaces[i].ifname);
818 for (var j = 0; j < ifnames.length; j++) {
819 if (ifnames[j].charAt(0) == '@')
822 if (isIgnoredIfname(ifnames[j]) || isVirtualIfname(ifnames[j]) || isWifiIfname(ifnames[j]))
825 devices[ifnames[j]] = this.instantiateDevice(ifnames[j]);
829 for (var ifname in _state.interfaces) {
830 if (devices.hasOwnProperty(ifname))
833 if (isIgnoredIfname(ifname) || isVirtualIfname(ifname) || isWifiIfname(ifname))
836 devices[ifname] = this.instantiateDevice(ifname);
839 /* find VLAN devices */
840 var uciSwitchVLANs = uci.sections('network', 'switch_vlan');
841 for (var i = 0; i < uciSwitchVLANs.length; i++) {
842 if (typeof(uciSwitchVLANs[i].ports) != 'string' ||
843 typeof(uciSwitchVLANs[i].device) != 'string' ||
844 !_state.switches.hasOwnProperty(uciSwitchVLANs[i].device))
847 var ports = uciSwitchVLANs[i].ports.split(/\s+/);
848 for (var j = 0; j < ports.length; j++) {
849 var m = ports[j].match(/^(\d+)([tu]?)$/);
853 var netdev = _state.switches[uciSwitchVLANs[i].device].netdevs[m[1]];
857 if (!devices.hasOwnProperty(netdev))
858 devices[netdev] = this.instantiateDevice(netdev);
860 _state.isSwitch[netdev] = true;
865 var vid = uciSwitchVLANs[i].vid || uciSwitchVLANs[i].vlan;
866 vid = (vid != null ? +vid : null);
868 if (vid == null || vid < 0 || vid > 4095)
871 var vlandev = '%s.%d'.format(netdev, vid);
873 if (!devices.hasOwnProperty(vlandev))
874 devices[vlandev] = this.instantiateDevice(vlandev);
876 _state.isSwitch[vlandev] = true;
880 /* find wireless interfaces */
881 var uciWifiIfaces = uci.sections('wireless', 'wifi-iface'),
884 for (var i = 0; i < uciWifiIfaces.length; i++) {
885 if (typeof(uciWifiIfaces[i].device) != 'string')
888 networkCount[uciWifiIfaces[i].device] = (networkCount[uciWifiIfaces[i].device] || 0) + 1;
890 var netid = '%s.network%d'.format(uciWifiIfaces[i].device, networkCount[uciWifiIfaces[i].device]);
892 devices[netid] = this.instantiateDevice(netid);
897 for (var netdev in devices)
898 if (devices.hasOwnProperty(netdev))
899 rv.push(devices[netdev]);
907 isIgnoredDevice: function(name) {
908 return isIgnoredIfname(name);
911 getWifiDevice: function(devname) {
912 return Promise.all([ getWifiIwinfoByIfname(devname, true), initNetworkState() ]).then(L.bind(function(res) {
913 var existingDevice = uci.get('wireless', devname);
915 if (existingDevice == null || existingDevice['.type'] != 'wifi-device')
918 return this.instantiateWifiDevice(devname, res[0]);
922 getWifiDevices: function() {
923 var deviceNames = [];
925 return initNetworkState().then(L.bind(function() {
926 var uciWifiDevices = uci.sections('wireless', 'wifi-device'),
929 for (var i = 0; i < uciWifiDevices.length; i++) {
930 tasks.push(callIwinfoInfo(uciWifiDevices['.name'], true));
931 deviceNames.push(uciWifiDevices['.name']);
934 return Promise.all(tasks);
935 }, this)).then(L.bind(function(iwinfos) {
938 for (var i = 0; i < deviceNames.length; i++)
939 if (L.isObject(iwinfos[i]))
940 rv.push(this.instantiateWifiDevice(deviceNames[i], iwinfos[i]));
942 rv.sort(function(a, b) { return a.getName() < b.getName() });
948 getWifiNetwork: function(netname) {
949 var sid, res, netid, radioname, radiostate, netstate;
951 return initNetworkState().then(L.bind(function() {
952 sid = getWifiSidByNetid(netname);
955 res = getWifiStateBySid(sid);
957 radioname = res ? res[0] : null;
958 radiostate = res ? res[1] : null;
959 netstate = res ? res[2] : null;
962 res = getWifiStateByIfname(netname);
968 sid = netstate.section;
969 netid = L.toArray(getWifiNetidBySid(sid))[0];
972 res = getWifiStateBySid(netname);
979 netid = L.toArray(getWifiNetidBySid(sid))[0];
982 res = getWifiNetidBySid(netname);
993 return (netstate ? getWifiIwinfoByIfname(netstate.ifname) : Promise.reject())
994 .catch(function() { return radioname ? getWifiIwinfoByIfname(radioname) : Promise.reject() })
995 .catch(function() { return Promise.resolve({ ifname: netid || sid || netname }) });
996 }, this)).then(L.bind(function(iwinfo) {
997 return this.instantiateWifiNetwork(sid || netname, radioname, radiostate, netid, netstate, iwinfo);
1001 addWifiNetwork: function(options) {
1002 return initNetworkState().then(L.bind(function() {
1003 if (options == null ||
1004 typeof(options) != 'object' ||
1005 typeof(options.device) != 'string')
1008 var existingDevice = uci.get('wireless', options.device);
1009 if (existingDevice == null || existingDevice['.type'] != 'wifi-device')
1012 var sid = uci.add('wireless', 'wifi-iface');
1013 for (var key in options)
1014 if (options.hasOwnProperty(key))
1015 uci.set('wireless', sid, key, options[key]);
1017 var radioname = existingDevice['.name'],
1018 netid = getWifiNetidBySid(sid) || [];
1020 return this.instantiateWifiNetwork(sid, radioname, _cache.wifi[radioname], netid[0], null, { ifname: netid });
1024 deleteWifiNetwork: function(netname) {
1025 return initNetworkState().then(L.bind(function() {
1026 var sid = getWifiSidByIfname(netname);
1031 uci.remove('wireless', sid);
1036 getStatusByRoute: function(addr, mask) {
1037 return initNetworkState().then(L.bind(function() {
1040 for (var i = 0; i < _state.interfacedump.length; i++) {
1041 if (!Array.isArray(_state.interfacedump[i].route))
1044 for (var j = 0; j < _state.interfacedump[i].route.length; j++) {
1045 if (typeof(_state.interfacedump[i].route[j]) != 'object' ||
1046 typeof(_state.interfacedump[i].route[j].target) != 'string' ||
1047 typeof(_state.interfacedump[i].route[j].mask) != 'number')
1050 if (_state.interfacedump[i].route[j].table)
1053 rv.push(_state.interfacedump[i]);
1061 getStatusByAddress: function(addr) {
1062 return initNetworkState().then(L.bind(function() {
1065 for (var i = 0; i < _state.interfacedump.length; i++) {
1066 if (Array.isArray(_state.interfacedump[i]['ipv4-address']))
1067 for (var j = 0; j < _state.interfacedump[i]['ipv4-address'].length; j++)
1068 if (typeof(_state.interfacedump[i]['ipv4-address'][j]) == 'object' &&
1069 _state.interfacedump[i]['ipv4-address'][j].address == addr)
1070 return _state.interfacedump[i];
1072 if (Array.isArray(_state.interfacedump[i]['ipv6-address']))
1073 for (var j = 0; j < _state.interfacedump[i]['ipv6-address'].length; j++)
1074 if (typeof(_state.interfacedump[i]['ipv6-address'][j]) == 'object' &&
1075 _state.interfacedump[i]['ipv6-address'][j].address == addr)
1076 return _state.interfacedump[i];
1078 if (Array.isArray(_state.interfacedump[i]['ipv6-prefix-assignment']))
1079 for (var j = 0; j < _state.interfacedump[i]['ipv6-prefix-assignment'].length; j++)
1080 if (typeof(_state.interfacedump[i]['ipv6-prefix-assignment'][j]) == 'object' &&
1081 typeof(_state.interfacedump[i]['ipv6-prefix-assignment'][j]['local-address']) == 'object' &&
1082 _state.interfacedump[i]['ipv6-prefix-assignment'][j]['local-address'].address == addr)
1083 return _state.interfacedump[i];
1090 getWANNetworks: function() {
1091 return this.getStatusByRoute('0.0.0.0', 0).then(L.bind(function(statuses) {
1094 for (var i = 0; i < statuses.length; i++)
1095 rv.push(this.instantiateNetwork(statuses[i].interface, statuses[i].proto));
1101 getWAN6Networks: function() {
1102 return this.getStatusByRoute('::', 0).then(L.bind(function(statuses) {
1105 for (var i = 0; i < statuses.length; i++)
1106 rv.push(this.instantiateNetwork(statuses[i].interface, statuses[i].proto));
1112 getSwitchTopologies: function() {
1113 return initNetworkState().then(function() {
1114 return _state.switches;
1118 instantiateNetwork: function(name, proto) {
1122 proto = (proto == null ? uci.get('network', name, 'proto') : proto);
1124 var protoClass = _protocols[proto] || Protocol;
1125 return new protoClass(name);
1128 instantiateDevice: function(name, network) {
1129 return new Device(name, network);
1132 instantiateWifiDevice: function(radioname, iwinfo) {
1133 return new WifiDevice(radioname, iwinfo);
1136 instantiateWifiNetwork: function(sid, radioname, radiostate, netid, netstate, iwinfo) {
1137 return new WifiNetwork(sid, radioname, radiostate, netid, netstate, iwinfo);
1141 Protocol = L.Class.extend({
1142 __init__: function(name) {
1146 _get: function(opt) {
1147 var val = uci.get('network', this.sid, opt);
1149 if (Array.isArray(val))
1150 return val.join(' ');
1155 _ubus: function(field) {
1156 for (var i = 0; i < _cache.interfacedump.length; i++) {
1157 if (_cache.interfacedump[i].interface != this.sid)
1160 return (field != null ? _cache.interfacedump[i][field] : _cache.interfacedump[i]);
1164 get: function(opt) {
1165 return uci.get('network', this.sid, opt);
1168 set: function(opt, val) {
1169 return uci.set('network', this.sid, opt, val);
1172 getIfname: function() {
1175 if (this.isFloating())
1176 ifname = this._ubus('l3_device');
1178 ifname = this._ubus('device');
1183 var res = getWifiNetidByNetname(this.sid);
1184 return (res != null ? res[0] : null);
1187 getProtocol: function() {
1191 getI18n: function() {
1192 switch (this.getProtocol()) {
1193 case 'none': return _('Unmanaged');
1194 case 'static': return _('Static address');
1195 case 'dhcp': return _('DHCP client');
1196 default: return _('Unknown');
1200 getType: function() {
1201 return this._get('type');
1204 getName: function() {
1208 getUptime: function() {
1209 return this._ubus('uptime') || 0;
1212 getExpiry: function() {
1213 var u = this._ubus('uptime'),
1214 d = this._ubus('data');
1216 if (typeof(u) == 'number' && d != null &&
1217 typeof(d) == 'object' && typeof(d.leasetime) == 'number') {
1218 var r = d.leasetime - (u % d.leasetime);
1219 return (r > 0 ? r : 0);
1225 getMetric: function() {
1226 return this._ubus('metric') || 0;
1229 getZoneName: function() {
1230 var d = this._ubus('data');
1232 if (L.isObject(d) && typeof(d.zone) == 'string')
1238 getIPAddr: function() {
1239 var addrs = this._ubus('ipv4-address');
1240 return ((Array.isArray(addrs) && addrs.length) ? addrs[0].address : null);
1243 getIPAddrs: function() {
1244 var addrs = this._ubus('ipv4-address'),
1247 if (Array.isArray(addrs))
1248 for (var i = 0; i < addrs.length; i++)
1249 rv.push('%s/%d'.format(addrs[i].address, addrs[i].mask));
1254 getNetmask: function() {
1255 var addrs = this._ubus('ipv4-address');
1256 if (Array.isArray(addrs) && addrs.length)
1257 return prefixToMask(addrs[0].mask, false);
1260 getGatewayAddr: function() {
1261 var routes = this._ubus('route');
1263 if (Array.isArray(routes))
1264 for (var i = 0; i < routes.length; i++)
1265 if (typeof(routes[i]) == 'object' &&
1266 routes[i].target == '0.0.0.0' &&
1267 routes[i].mask == 0)
1268 return routes[i].nexthop;
1273 getDNSAddrs: function() {
1274 var addrs = this._ubus('dns-server'),
1277 if (Array.isArray(addrs))
1278 for (var i = 0; i < addrs.length; i++)
1279 if (!/:/.test(addrs[i]))
1285 getIP6Addr: function() {
1286 var addrs = this._ubus('ipv6-address');
1288 if (Array.isArray(addrs) && L.isObject(addrs[0]))
1289 return '%s/%d'.format(addrs[0].address, addrs[0].mask);
1291 addrs = this._ubus('ipv6-prefix-assignment');
1293 if (Array.isArray(addrs) && L.isObject(addrs[0]) && L.isObject(addrs[0]['local-address']))
1294 return '%s/%d'.format(addrs[0]['local-address'].address, addrs[0]['local-address'].mask);
1299 getIP6Addrs: function() {
1300 var addrs = this._ubus('ipv6-address'),
1303 if (Array.isArray(addrs))
1304 for (var i = 0; i < addrs.length; i++)
1305 if (L.isObject(addrs[i]))
1306 rv.push('%s/%d'.format(addrs[i].address, addrs[i].mask));
1308 addrs = this._ubus('ipv6-prefix-assignment');
1310 if (Array.isArray(addrs))
1311 for (var i = 0; i < addrs.length; i++)
1312 if (L.isObject(addrs[i]) && L.isObject(addrs[i]['local-address']))
1313 rv.push('%s/%d'.format(addrs[i]['local-address'].address, addrs[i]['local-address'].mask));
1318 getDNS6Addrs: function() {
1319 var addrs = this._ubus('dns-server'),
1322 if (Array.isArray(addrs))
1323 for (var i = 0; i < addrs.length; i++)
1324 if (/:/.test(addrs[i]))
1330 getIP6Prefix: function() {
1331 var prefixes = this._ubus('ipv6-prefix');
1333 if (Array.isArray(prefixes) && L.isObject(prefixes[0]))
1334 return '%s/%d'.format(prefixes[0].address, prefixes[0].mask);
1339 getErrors: function() {
1340 var errors = this._ubus('errors'),
1343 if (Array.isArray(errors)) {
1344 for (var i = 0; i < errors.length; i++) {
1345 if (!L.isObject(errors[i]) || typeof(errors[i].code) != 'string')
1349 rv.push(proto_errors[errors[i].code] || _('Unknown error (%s)').format(errors[i].code));
1356 isBridge: function() {
1357 return (!this.isVirtual() && this.getType() == 'bridge');
1360 getOpkgPackage: function() {
1364 isInstalled: function() {
1368 isVirtual: function() {
1372 isFloating: function() {
1376 isDynamic: function() {
1377 return (this._ubus('dynamic') == true);
1380 isAlias: function() {
1381 var ifnames = L.toArray(uci.get('network', this.sid, 'ifname')),
1384 for (var i = 0; i < ifnames.length; i++)
1385 if (ifnames[i].charAt(0) == '@')
1386 parent = ifnames[i].substr(1);
1387 else if (parent != null)
1393 isEmpty: function() {
1394 if (this.isFloating())
1398 ifname = this._get('ifname');
1400 if (ifname != null && ifname.match(/\S+/))
1403 if (empty == true && getWifiNetidBySid(this.sid) != null)
1410 return (this._ubus('up') == true);
1413 addDevice: function(ifname) {
1414 ifname = ifnameOf(ifname);
1416 if (ifname == null || this.isFloating())
1419 var wif = getWifiSidByIfname(ifname);
1422 return appendValue('wireless', wif, 'network', this.sid);
1424 return appendValue('network', this.sid, 'ifname', ifname);
1427 deleteDevice: function(ifname) {
1430 ifname = ifnameOf(ifname);
1432 if (ifname == null || this.isFloating())
1435 var wif = getWifiSidByIfname(ifname);
1438 rv = removeValue('wireless', wif, 'network', this.sid);
1440 if (removeValue('network', this.sid, 'ifname', ifname))
1446 getDevice: function() {
1447 if (this.isVirtual()) {
1448 var ifname = '%s-%s'.format(this.getProtocol(), this.sid);
1449 _state.isTunnel[this.getProtocol() + '-' + this.sid] = true;
1450 return L.network.instantiateDevice(ifname, this);
1452 else if (this.isBridge()) {
1453 var ifname = 'br-%s'.format(this.sid);
1454 _state.isBridge[ifname] = true;
1455 return new Device(ifname, this);
1458 var ifname = this._ubus('l3_device') || this._ubus('device');
1461 return L.network.instantiateDevice(ifname, this);
1463 var ifnames = L.toArray(uci.get('network', this.sid, 'ifname'));
1465 for (var i = 0; i < ifnames.length; i++) {
1466 var m = ifnames[i].match(/^([^:/]+)/);
1467 return ((m && m[1]) ? L.network.instantiateDevice(m[1], this) : null);
1470 ifname = getWifiNetidByNetname(this.sid);
1472 return (ifname != null ? L.network.instantiateDevice(ifname[0], this) : null);
1476 getDevices: function() {
1479 if (!this.isBridge() && !(this.isVirtual() && !this.isFloating()))
1482 var ifnames = L.toArray(uci.get('network', this.sid, 'ifname'));
1484 for (var i = 0; i < ifnames.length; i++) {
1485 if (ifnames[i].charAt(0) == '@')
1488 var m = ifnames[i].match(/^([^:/]+)/);
1490 rv.push(L.network.instantiateDevice(m[1], this));
1493 var uciWifiIfaces = uci.sections('wireless', 'wifi-iface');
1495 for (var i = 0; i < uciWifiIfaces.length; i++) {
1496 if (typeof(uciWifiIfaces[i].device) != 'string')
1499 var networks = L.toArray(uciWifiIfaces[i].network);
1501 for (var j = 0; j < networks.length; j++) {
1502 if (networks[j] != this.sid)
1505 var netid = getWifiNetidBySid(uciWifiIfaces[i]['.name']);
1508 rv.push(L.network.instantiateDevice(netid[0], this));
1512 rv.sort(deviceSort);
1517 containsDevice: function(ifname) {
1518 ifname = ifnameOf(ifname);
1522 else if (this.isVirtual() && '%s-%s'.format(this.getProtocol(), this.sid) == ifname)
1524 else if (this.isBridge() && 'br-%s'.format(this.sid) == ifname)
1527 var ifnames = L.toArray(uci.get('network', this.sid, 'ifname'));
1529 for (var i = 0; i < ifnames.length; i++) {
1530 var m = ifnames[i].match(/^([^:/]+)/);
1531 if (m != null && m[1] == ifname)
1535 var wif = getWifiSidByIfname(ifname);
1538 var networks = L.toArray(uci.get('wireless', wif, 'network'));
1540 for (var i = 0; i < networks.length; i++)
1541 if (networks[i] == this.sid)
1549 Device = L.Class.extend({
1550 __init__: function(ifname, network) {
1551 var wif = getWifiSidByIfname(ifname);
1554 var res = getWifiStateBySid(wif) || [],
1555 netid = getWifiNetidBySid(wif) || [];
1557 this.wif = new WifiNetwork(wif, res[0], res[1], netid[0], res[2], { ifname: ifname });
1558 this.ifname = this.wif.getIfname();
1561 this.ifname = this.ifname || ifname;
1562 this.dev = _state.interfaces[this.ifname];
1563 this.network = network;
1566 _ubus: function(field) {
1567 var dump = _cache.devicedump[this.ifname] || {};
1569 return (field != null ? dump[field] : dump);
1572 getName: function() {
1573 return (this.wif != null ? this.wif.getIfname() : this.ifname);
1576 getMAC: function() {
1577 return this._ubus('macaddr');
1580 getIPAddrs: function() {
1581 var addrs = (this.dev != null ? this.dev.ipaddrs : null);
1582 return (Array.isArray(addrs) ? addrs : []);
1585 getIP6Addrs: function() {
1586 var addrs = (this.dev != null ? this.dev.ip6addrs : null);
1587 return (Array.isArray(addrs) ? addrs : []);
1590 getType: function() {
1591 if (this.ifname != null && this.ifname.charAt(0) == '@')
1593 else if (this.wif != null || isWifiIfname(this.ifname))
1595 else if (_state.isBridge[this.ifname])
1597 else if (_state.isTunnel[this.ifname])
1599 else if (this.ifname.indexOf('.') > -1)
1601 else if (_state.isSwitch[this.ifname])
1607 getShortName: function() {
1608 if (this.wif != null)
1609 return this.wif.getShortName();
1614 getI18n: function() {
1615 if (this.wif != null) {
1616 return '%s: %s "%s"'.format(
1617 _('Wireless Network'),
1618 this.wif.getActiveMode(),
1619 this.wif.getActiveSSID() || this.wif.getActiveBSSID() || this.wif.getID() || '?');
1622 return '%s: "%s"'.format(this.getTypeI18n(), this.getName());
1625 getTypeI18n: function() {
1626 switch (this.getType()) {
1628 return _('Alias Interface');
1631 return _('Wireless Adapter');
1637 return _('Ethernet Switch');
1640 return (_state.isSwitch[this.ifname] ? _('Switch VLAN') : _('Software VLAN'));
1643 return _('Tunnel Interface');
1646 return _('Ethernet Adapter');
1650 getPorts: function() {
1651 var br = _state.bridges[this.ifname],
1654 if (br == null || !Array.isArray(br.ifnames))
1657 for (var i = 0; i < br.ifnames.length; i++)
1658 rv.push(L.network.instantiateDevice(br.ifnames[i]));
1663 getBridgeID: function() {
1664 var br = _state.bridges[this.ifname];
1665 return (br != null ? br.id : null);
1668 getBridgeSTP: function() {
1669 var br = _state.bridges[this.ifname];
1670 return (br != null ? !!br.stp : false);
1674 var up = this._ubus('up');
1677 up = (this.getType() == 'alias');
1682 isBridge: function() {
1683 return (this.getType() == 'bridge');
1686 isBridgePort: function() {
1687 return (this.dev != null && this.dev.bridge != null);
1690 getTXBytes: function() {
1691 var stat = this._ubus('statistics');
1692 return (stat != null ? stat.tx_bytes || 0 : 0);
1695 getRXBytes: function() {
1696 var stat = this._ubus('statistics');
1697 return (stat != null ? stat.rx_bytes || 0 : 0);
1700 getTXPackets: function() {
1701 var stat = this._ubus('statistics');
1702 return (stat != null ? stat.tx_packets || 0 : 0);
1705 getRXPackets: function() {
1706 var stat = this._ubus('statistics');
1707 return (stat != null ? stat.rx_packets || 0 : 0);
1710 getNetwork: function() {
1711 return this.getNetworks()[0];
1714 getNetworks: function() {
1715 if (this.networks == null) {
1718 var networks = L.network.getNetworks();
1720 for (var i = 0; i < networks.length; i++)
1721 if (networks[i].containsDevice(this.ifname) || networks[i].getIfname() == this.ifname)
1722 this.networks.push(networks[i]);
1724 this.networks.sort(networkSort);
1727 return this.networks;
1730 getWifiNetwork: function() {
1731 return (this.wif != null ? this.wif : null);
1735 WifiDevice = L.Class.extend({
1736 __init__: function(name, iwinfo) {
1737 var uciWifiDevice = uci.get('wireless', name);
1739 if (uciWifiDevice != null &&
1740 uciWifiDevice['.type'] == 'wifi-device' &&
1741 uciWifiDevice['.name'] != null) {
1742 this.sid = uciWifiDevice['.name'];
1743 this.iwinfo = iwinfo;
1746 this.sid = this.sid || name;
1747 this.iwinfo = this.iwinfo || { ifname: this.sid };
1750 get: function(opt) {
1751 return uci.get('wireless', this.sid, opt);
1754 set: function(opt, value) {
1755 return uci.set('wireless', this.sid, opt, value);
1758 getName: function() {
1762 getHWModes: function() {
1763 if (L.isObject(this.iwinfo.hwmodelist))
1764 for (var k in this.iwinfo.hwmodelist)
1765 return this.iwinfo.hwmodelist;
1767 return { b: true, g: true };
1770 getI18n: function() {
1771 var type = this.iwinfo.hardware_name || 'Generic';
1773 if (this.iwinfo.type == 'wl')
1776 var hwmodes = this.getHWModes(),
1779 if (hwmodes.a) modestr += 'a';
1780 if (hwmodes.b) modestr += 'b';
1781 if (hwmodes.g) modestr += 'g';
1782 if (hwmodes.n) modestr += 'n';
1783 if (hwmodes.ad) modestr += 'ac';
1785 return '%s 802.11%s Wireless Controller (%s)'.format(type, modestr, this.getName());
1789 if (L.isObject(_cache.wifi[this.sid]))
1790 return (_cache.wifi[this.sid].up == true);
1795 getWifiNetwork: function(network) {
1796 return L.network.getWifiNetwork(network).then(L.bind(function(networkInstance) {
1797 var uciWifiIface = (networkInstance.sid ? uci.get('wireless', networkInstance.sid) : null);
1799 if (uciWifiIface == null || uciWifiIface['.type'] != 'wifi-iface' || uciWifiIface.device != this.sid)
1800 return Promise.reject();
1802 return networkInstance;
1806 getWifiNetworks: function() {
1807 var uciWifiIfaces = uci.sections('wireless', 'wifi-iface'),
1810 for (var i = 0; i < uciWifiIfaces.length; i++)
1811 if (uciWifiIfaces[i].device == this.sid)
1812 tasks.push(L.network.getWifiNetwork(uciWifiIfaces[i]['.name']));
1814 return Promise.all(tasks);
1817 addWifiNetwork: function(options) {
1818 if (!L.isObject(options))
1821 options.device = this.sid;
1823 return L.network.addWifiNetwork(options);
1826 deleteWifiNetwork: function(network) {
1829 if (network instanceof WifiNetwork) {
1833 var uciWifiIface = uci.get('wireless', network);
1835 if (uciWifiIface == null || uciWifiIface['.type'] != 'wifi-iface')
1836 sid = getWifiSidByIfname(network);
1839 if (sid == null || uci.get('wireless', sid, 'device') != this.sid)
1840 return Promise.resolve(false);
1842 uci.delete('wireless', network);
1844 return Promise.resolve(true);
1848 WifiNetwork = L.Class.extend({
1849 __init__: function(sid, radioname, radiostate, netid, netstate, iwinfo) {
1851 this.wdev = iwinfo.ifname;
1852 this.iwinfo = iwinfo;
1861 ubus: function(/* ... */) {
1862 var v = this._ubusdata;
1864 for (var i = 0; i < arguments.length; i++)
1866 v = v[arguments[i]];
1873 get: function(opt) {
1874 return uci.get('wireless', this.sid, opt);
1877 set: function(opt, value) {
1878 return uci.set('wireless', this.sid, opt, value);
1881 getMode: function() {
1882 return this.ubus('net', 'config', 'mode') || this.get('mode') || 'ap';
1885 getSSID: function() {
1886 return this.ubus('net', 'config', 'ssid') || this.get('ssid');
1889 getBSSID: function() {
1890 return this.ubus('net', 'config', 'bssid') || this.get('bssid');
1893 getNetworkNames: function() {
1894 return L.toArray(this.ubus('net', 'config', 'network') || this.get('network'));
1901 getName: function() {
1905 getIfname: function() {
1906 var ifname = this.ubus('net', 'ifname') || this.iwinfo.ifname;
1908 if (ifname == null || ifname.match(/^(wifi|radio)\d/))
1909 ifname = this.netid;
1914 getWifiDevice: function() {
1915 var radioname = this.ubus('radio') || this.get('device');
1917 if (radioname == null)
1918 return Promise.reject();
1920 return L.network.getWifiDevice(radioname);
1924 var device = this.getDevice();
1929 return device.isUp();
1932 getActiveMode: function() {
1933 var mode = this.iwinfo.mode || this.ubus('net', 'config', 'mode') || this.get('mode') || 'ap';
1936 case 'ap': return 'Master';
1937 case 'sta': return 'Client';
1938 case 'adhoc': return 'Ad-Hoc';
1939 case 'mesh': return 'Mesh';
1940 case 'monitor': return 'Monitor';
1941 default: return mode;
1945 getActiveModeI18n: function() {
1946 var mode = this.getActiveMode();
1949 case 'Master': return _('Master');
1950 case 'Client': return _('Client');
1951 case 'Ad-Hoc': return _('Ad-Hoc');
1952 case 'Mash': return _('Mesh');
1953 case 'Monitor': return _('Monitor');
1954 default: return mode;
1958 getActiveSSID: function() {
1959 return this.iwinfo.ssid || this.ubus('net', 'config', 'ssid') || this.get('ssid');
1962 getActiveBSSID: function() {
1963 return this.iwinfo.bssid || this.ubus('net', 'config', 'bssid') || this.get('bssid');
1966 getActiveEncryption: function() {
1967 var encryption = this.iwinfo.encryption;
1969 return (L.isObject(encryption) ? encryption.description || '-' : '-');
1972 getAssocList: function() {
1976 getFrequency: function() {
1977 var freq = this.iwinfo.frequency;
1979 if (freq != null && freq > 0)
1980 return '%.03f'.format(freq / 1000);
1985 getBitRate: function() {
1986 var rate = this.iwinfo.bitrate;
1988 if (rate != null && rate > 0)
1989 return (rate / 1000);
1994 getChannel: function() {
1995 return this.iwinfo.channel || this.ubus('dev', 'config', 'channel') || this.get('channel');
1998 getSignal: function() {
1999 return this.iwinfo.signal || 0;
2002 getNoise: function() {
2003 return this.iwinfo.noise || 0;
2006 getCountryCode: function() {
2007 return this.iwinfo.country || this.ubus('dev', 'config', 'country') || '00';
2010 getTXPower: function() {
2011 var pwr = this.iwinfo.txpower || 0;
2012 return (pwr + this.getTXPowerOffset());
2015 getTXPowerOffset: function() {
2016 return this.iwinfo.txpower_offset || 0;
2019 getSignalLevel: function(signal, noise) {
2020 if (this.getActiveBSSID() == '00:00:00:00:00:00')
2023 signal = signal || this.getSignal();
2024 noise = noise || this.getNoise();
2026 if (signal < 0 && noise < 0) {
2027 var snr = -1 * (noise - signal);
2028 return Math.floor(snr / 5);
2034 getSignalPercent: function() {
2035 var qc = this.iwinfo.quality || 0,
2036 qm = this.iwinfo.quality_max || 0;
2038 if (qc > 0 && qm > 0)
2039 return Math.floor((100 / qm) * qc);
2044 getShortName: function() {
2045 return '%s "%s"'.format(
2046 this.getActiveModeI18n(),
2047 this.getActiveSSID() || this.getActiveBSSID() || this.getID());
2050 getI18n: function() {
2051 return '%s: %s "%s" (%s)'.format(
2052 _('Wireless Network'),
2053 this.getActiveModeI18n(),
2054 this.getActiveSSID() || this.getActiveBSSID() || this.getID(),
2058 getNetwork: function() {
2059 return this.getNetworks()[0];
2062 getNetworks: function() {
2063 var networkNames = this.getNetworkNames(),
2066 for (var i = 0; i < networkNames.length; i++) {
2067 var uciInterface = uci.get('network', networkNames[i]);
2069 if (uciInterface == null || uciInterface['.type'] != 'interface')
2072 networks.push(L.network.instantiateNetwork(networkNames[i]));
2075 networks.sort(networkSort);
2080 getDevice: function() {
2081 return L.network.instantiateDevice(this.getIfname());