summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-mod-network/htdocs
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-mod-network/htdocs')
-rw-r--r--modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js419
-rw-r--r--modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js27
-rw-r--r--modules/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js17
-rw-r--r--modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js187
4 files changed, 330 insertions, 320 deletions
diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js b/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js
index 5ed55e24fc..d008feb56a 100644
--- a/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js
+++ b/modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js
@@ -46,11 +46,15 @@ function validateQoSMap(section_id, value) {
return true;
}
-function deviceSectionExists(section_id, devname, devtype) {
+function deviceSectionExists(section_id, devname, ignore_type_match) {
var exists = false;
uci.sections('network', 'device', function(ss) {
- exists = exists || (ss['.name'] != section_id && ss.name == devname && (!devtype || devtype == ss.type));
+ exists = exists || (
+ ss['.name'] != section_id &&
+ ss.name == devname &&
+ (!ignore_type_match || !ignore_type_match.test(ss.type || ''))
+ );
});
return exists;
@@ -385,148 +389,68 @@ return baseclass.extend({
},
addDeviceOptions: function(s, dev, isNew) {
- var isIface = (s.sectiontype == 'interface'),
- ifc = isIface ? network.instantiateNetwork(s.section) : null,
- gensection = ifc ? 'physical' : 'devgeneral',
- advsection = ifc ? 'physical' : 'devadvanced',
- simpledep = ifc ? { type: '', ifname_single: /^[^@]/ } : { type: '' },
- disableLegacyBridging = isIface && deviceSectionExists(null, 'br-%s'.format(ifc.getName()), 'bridge'),
- o, ss;
-
- if (isIface) {
- if (!s.hasOwnProperty('parse'))
- s.parse = sectionParse;
-
- var type;
-
- /* If an externally configured br-xxx interface already exists,
- * then disable legacy bridge configuration */
- if (disableLegacyBridging) {
- type = this.addOption(s, gensection, form.HiddenValue, 'type');
- type.cfgvalue = function() { return '' };
- }
- else {
- type = this.addOption(s, gensection, form.Flag, 'type', _('Bridge interfaces'), _('Creates a bridge over specified interface(s)'));
- }
-
- type.modalonly = true;
- type.disabled = '';
- type.enabled = 'bridge';
- type.write = type.remove = function(section_id, value) {
- var protoname = this.section.formvalue(section_id, 'proto'),
- protocol = network.getProtocol(protoname),
- new_ifnames = this.isActive(section_id) ? L.toArray(this.section.formvalue(section_id, value ? 'ifname_multi' : 'ifname_single')) : [];
-
- if (!protocol.isVirtual() && !this.isActive(section_id))
- return;
-
- var old_ifnames = [],
- devs = ifc.getDevices() || L.toArray(ifc.getDevice());
-
- for (var i = 0; i < devs.length; i++)
- old_ifnames.push(devs[i].getName());
-
- if (!value)
- new_ifnames.length = Math.max(new_ifnames.length, 1);
+ var o, ss;
- old_ifnames.sort();
- new_ifnames.sort();
+ s.tab('devgeneral', _('General device options'));
+ s.tab('devadvanced', _('Advanced device options'));
+ s.tab('brport', _('Bridge port specific options'));
+ s.tab('bridgevlan', _('Bridge VLAN filtering'));
- for (var i = 0; i < Math.max(old_ifnames.length, new_ifnames.length); i++) {
- if (old_ifnames[i] != new_ifnames[i]) {
- // backup_ifnames()
- for (var j = 0; j < old_ifnames.length; j++)
- ifc.deleteDevice(old_ifnames[j]);
-
- for (var j = 0; j < new_ifnames.length; j++)
- ifc.addDevice(new_ifnames[j]);
-
- break;
- }
- }
-
- if (value)
- uci.set('network', section_id, 'type', 'bridge');
- else
- uci.unset('network', section_id, 'type');
- };
- }
- else {
- s.tab('devgeneral', _('General device options'));
- s.tab('devadvanced', _('Advanced device options'));
- s.tab('brport', _('Bridge port specific options'));
- s.tab('bridgevlan', _('Bridge VLAN filtering'));
-
- o = this.addOption(s, gensection, form.ListValue, 'type', _('Device type'));
- o.readonly = !isNew;
- o.value('', _('Network device'));
- o.value('bridge', _('Bridge device'));
- o.value('8021q', _('VLAN (802.1q)'));
- o.value('8021ad', _('VLAN (802.1ad)'));
- o.value('macvlan', _('MAC VLAN'));
- o.value('veth', _('Virtual Ethernet'));
-
- o = this.addOption(s, gensection, widgets.DeviceSelect, 'name_simple', _('Existing device'));
- o.readonly = !isNew;
- o.rmempty = false;
- o.noaliases = true;
- o.default = (dev ? dev.getName() : '');
- o.ucioption = 'name';
- o.write = o.remove = setIfActive;
- o.filter = function(section_id, value) {
- return !deviceSectionExists(section_id, value);
- };
- o.validate = function(section_id, value) {
- return deviceSectionExists(section_id, value) ? _('A configuration for the device "%s" already exists').format(value) : true;
- };
- o.depends('type', '');
- }
+ o = this.addOption(s, 'devgeneral', form.ListValue, 'type', _('Device type'));
+ o.readonly = !isNew;
+ o.value('', _('Network device'));
+ o.value('bridge', _('Bridge device'));
+ o.value('8021q', _('VLAN (802.1q)'));
+ o.value('8021ad', _('VLAN (802.1ad)'));
+ o.value('macvlan', _('MAC VLAN'));
+ o.value('veth', _('Virtual Ethernet'));
+
+ o = this.addOption(s, 'devgeneral', widgets.DeviceSelect, 'name_simple', _('Existing device'));
+ o.readonly = !isNew;
+ o.rmempty = false;
+ o.noaliases = true;
+ o.default = (dev ? dev.getName() : '');
+ o.ucioption = 'name';
+ o.write = o.remove = setIfActive;
+ o.filter = function(section_id, value) {
+ return !deviceSectionExists(section_id, value, /^(?:bridge|8021q|8021ad|macvlan|veth)$/);
+ };
+ o.validate = function(section_id, value) {
+ return deviceSectionExists(section_id, value, /^(?:bridge|8021q|8021ad|macvlan|veth)$/)
+ ? _('A configuration for the device "%s" already exists').format(value) : true;
+ };
+ o.depends('type', '');
- o = this.addOption(s, gensection, widgets.DeviceSelect, 'ifname_single', isIface ? _('Interface') : _('Base device'));
+ o = this.addOption(s, 'devgeneral', widgets.DeviceSelect, 'ifname_single', _('Base device'));
o.readonly = !isNew;
o.rmempty = false;
- o.noaliases = !isIface;
+ o.noaliases = true;
o.default = (dev ? dev.getName() : '').match(/^.+\.\d+$/) ? dev.getName().replace(/\.\d+$/, '') : '';
o.ucioption = 'ifname';
o.validate = function(section_id, value) {
- var type = this.section.formvalue(section_id, 'type'),
- name = this.section.getUIElement(section_id, 'name_complex');
+ if (isNew) {
+ var type = this.section.formvalue(section_id, 'type'),
+ name = this.section.getUIElement(section_id, 'name_complex');
- if (type == 'macvlan' && value && name && !name.isChanged()) {
- var i = 0;
+ if (type == 'macvlan' && value && name && !name.isChanged()) {
+ var i = 0;
- while (deviceSectionExists(section_id, '%smac%d'.format(value, i)))
- i++;
+ while (deviceSectionExists(section_id, '%smac%d'.format(value, i)))
+ i++;
- name.setValue('%smac%d'.format(value, i));
- name.triggerValidation();
+ name.setValue('%smac%d'.format(value, i));
+ name.triggerValidation();
+ }
}
return true;
};
- if (isIface) {
- o.write = o.remove = function() {};
- o.cfgvalue = function(section_id) {
- return (ifc.getDevices() || L.toArray(ifc.getDevice())).map(function(dev) {
- return dev.getName();
- });
- };
- o.onchange = function(ev, section_id, values) {
- for (var i = 0, co; (co = this.section.children[i]) != null; i++)
- if (co !== this && co.refresh)
- co.refresh(section_id);
-
- };
- o.depends('type', '');
- }
- else {
- o.write = o.remove = setIfActive;
- o.depends('type', '8021q');
- o.depends('type', '8021ad');
- o.depends('type', 'macvlan');
- }
+ o.write = o.remove = setIfActive;
+ o.depends('type', '8021q');
+ o.depends('type', '8021ad');
+ o.depends('type', 'macvlan');
- o = this.addOption(s, gensection, form.Value, 'vid', _('VLAN ID'));
+ o = this.addOption(s, 'devgeneral', form.Value, 'vid', _('VLAN ID'));
o.readonly = !isNew;
o.datatype = 'range(1, 4094)';
o.rmempty = false;
@@ -546,74 +470,64 @@ return baseclass.extend({
o.depends('type', '8021q');
o.depends('type', '8021ad');
- o = this.addOption(s, gensection, form.ListValue, 'mode', _('Mode'));
+ o = this.addOption(s, 'devgeneral', form.ListValue, 'mode', _('Mode'));
o.value('vepa', _('VEPA (Virtual Ethernet Port Aggregator)', 'MACVLAN mode'));
o.value('private', _('Private (Prevent communication between MAC VLANs)', 'MACVLAN mode'));
o.value('bridge', _('Bridge (Support direct communication between MAC VLANs)', 'MACVLAN mode'));
o.value('passthru', _('Pass-through (Mirror physical device to single MAC VLAN)', 'MACVLAN mode'));
o.depends('type', 'macvlan');
- if (!isIface) {
- o = this.addOption(s, gensection, form.Value, 'name_complex', _('Device name'));
- o.rmempty = false;
- o.datatype = 'maxlength(15)';
- o.readonly = !isNew;
- o.ucioption = 'name';
- o.write = o.remove = setIfActive;
- o.validate = function(section_id, value) {
- return deviceSectionExists(section_id, value) ? _('The device name "%s" is already taken').format(value) : true;
- };
- o.depends({ type: '', '!reverse': true });
- }
+ o = this.addOption(s, 'devgeneral', form.Value, 'name_complex', _('Device name'));
+ o.rmempty = false;
+ o.datatype = 'maxlength(15)';
+ o.readonly = !isNew;
+ o.ucioption = 'name';
+ o.write = o.remove = setIfActive;
+ o.validate = function(section_id, value) {
+ return deviceSectionExists(section_id, value, /^$/) ? _('The device name "%s" is already taken').format(value) : true;
+ };
+ o.depends({ type: '', '!reverse': true });
- o = this.addOption(s, advsection, form.DynamicList, 'ingress_qos_mapping', _('Ingress QoS mapping'), _('Defines a mapping of VLAN header priority to the Linux internal packet priority on incoming frames'));
+ o = this.addOption(s, 'devadvanced', form.DynamicList, 'ingress_qos_mapping', _('Ingress QoS mapping'), _('Defines a mapping of VLAN header priority to the Linux internal packet priority on incoming frames'));
o.rmempty = true;
o.validate = validateQoSMap;
o.depends('type', '8021q');
o.depends('type', '8021ad');
- o = this.addOption(s, advsection, form.DynamicList, 'egress_qos_mapping', _('Egress QoS mapping'), _('Defines a mapping of Linux internal packet priority to VLAN header priority but for outgoing frames'));
+ o = this.addOption(s, 'devadvanced', form.DynamicList, 'egress_qos_mapping', _('Egress QoS mapping'), _('Defines a mapping of Linux internal packet priority to VLAN header priority but for outgoing frames'));
o.rmempty = true;
o.validate = validateQoSMap;
o.depends('type', '8021q');
o.depends('type', '8021ad');
- o = this.addOption(s, gensection, widgets.DeviceSelect, 'ifname_multi', _('Bridge ports'));
+ o = this.addOption(s, 'devgeneral', widgets.DeviceSelect, 'ifname_multi', _('Bridge ports'));
o.size = 10;
o.rmempty = true;
o.multiple = true;
o.noaliases = true;
o.nobridges = true;
- o.ucioption = 'ifname';
- if (isIface) {
- o.write = o.remove = function() {};
- o.cfgvalue = function(section_id) {
- return (ifc.getDevices() || L.toArray(ifc.getDevice())).map(function(dev) { return dev.getName() });
- };
- }
- else {
- o.write = o.remove = setIfActive;
- o.default = L.toArray(dev ? dev.getPorts() : null).filter(function(p) { return p.getType() != 'wifi' }).map(function(p) { return p.getName() });
- o.filter = function(section_id, device_name) {
- var bridge_name = uci.get('network', section_id, 'name'),
- choice_dev = network.instantiateDevice(device_name),
- parent_dev = choice_dev.getParent();
-
- /* only show wifi networks which are already present in "option ifname" */
- if (choice_dev.getType() == 'wifi') {
- var ifnames = L.toArray(uci.get('network', section_id, 'ifname'));
-
- for (var i = 0; i < ifnames.length; i++)
- if (ifnames[i] == device_name)
- return true;
-
- return false;
- }
+ o.ucioption = 'ports';
+ o.write = o.remove = setIfActive;
+ o.default = L.toArray(dev ? dev.getPorts() : null).filter(function(p) { return p.getType() != 'wifi' }).map(function(p) { return p.getName() });
+ o.filter = function(section_id, device_name) {
+ var bridge_name = uci.get('network', section_id, 'name'),
+ choice_dev = network.instantiateDevice(device_name),
+ parent_dev = choice_dev.getParent();
+
+ /* only show wifi networks which are already present in "option ifname" */
+ if (choice_dev.getType() == 'wifi') {
+ var ifnames = L.toArray(uci.get('network', section_id, 'ports'));
+
+ for (var i = 0; i < ifnames.length; i++)
+ if (ifnames[i] == device_name)
+ return true;
+
+ return false;
+ }
- return (!parent_dev || parent_dev.getName() != bridge_name);
- };
- o.description = _('Specifies the wired ports to attach to this bridge. In order to attach wireless networks, choose the associated interface as network in the wireless settings.')
- }
+ return (!parent_dev || parent_dev.getName() != bridge_name);
+ };
+ o.description = _('Specifies the wired ports to attach to this bridge. In order to attach wireless networks, choose the associated interface as network in the wireless settings.')
o.onchange = function(ev, section_id, values) {
ss.updatePorts(values);
@@ -623,64 +537,64 @@ return baseclass.extend({
};
o.depends('type', 'bridge');
- o = this.replaceOption(s, gensection, form.Flag, 'bridge_empty', _('Bring up empty bridge'), _('Bring up the bridge interface even if no ports are attached'));
+ o = this.replaceOption(s, 'devgeneral', form.Flag, 'bridge_empty', _('Bring up empty bridge'), _('Bring up the bridge interface even if no ports are attached'));
o.default = o.disabled;
o.depends('type', 'bridge');
- o = this.replaceOption(s, advsection, form.Value, 'priority', _('Priority'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'priority', _('Priority'));
o.placeholder = '32767';
o.datatype = 'range(0, 65535)';
o.depends('type', 'bridge');
- o = this.replaceOption(s, advsection, form.Value, 'ageing_time', _('Ageing time'), _('Timeout in seconds for learned MAC addresses in the forwarding database'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'ageing_time', _('Ageing time'), _('Timeout in seconds for learned MAC addresses in the forwarding database'));
o.placeholder = '30';
o.datatype = 'uinteger';
o.depends('type', 'bridge');
- o = this.replaceOption(s, advsection, form.Flag, 'stp', _('Enable <abbr title="Spanning Tree Protocol">STP</abbr>'), _('Enables the Spanning Tree Protocol on this bridge'));
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'stp', _('Enable <abbr title="Spanning Tree Protocol">STP</abbr>'), _('Enables the Spanning Tree Protocol on this bridge'));
o.default = o.disabled;
o.depends('type', 'bridge');
- o = this.replaceOption(s, advsection, form.Value, 'hello_time', _('Hello interval'), _('Interval in seconds for STP hello packets'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'hello_time', _('Hello interval'), _('Interval in seconds for STP hello packets'));
o.placeholder = '2';
o.datatype = 'range(1, 10)';
o.depends({ type: 'bridge', stp: '1' });
- o = this.replaceOption(s, advsection, form.Value, 'forward_delay', _('Forward delay'), _('Time in seconds to spend in listening and learning states'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'forward_delay', _('Forward delay'), _('Time in seconds to spend in listening and learning states'));
o.placeholder = '15';
o.datatype = 'range(2, 30)';
o.depends({ type: 'bridge', stp: '1' });
- o = this.replaceOption(s, advsection, form.Value, 'max_age', _('Maximum age'), _('Timeout in seconds until topology updates on link loss'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'max_age', _('Maximum age'), _('Timeout in seconds until topology updates on link loss'));
o.placeholder = '20';
o.datatype = 'range(6, 40)';
o.depends({ type: 'bridge', stp: '1' });
- o = this.replaceOption(s, advsection, form.Flag, 'igmp_snooping', _('Enable <abbr title="Internet Group Management Protocol">IGMP</abbr> snooping'), _('Enables IGMP snooping on this bridge'));
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'igmp_snooping', _('Enable <abbr title="Internet Group Management Protocol">IGMP</abbr> snooping'), _('Enables IGMP snooping on this bridge'));
o.default = o.disabled;
o.depends('type', 'bridge');
- o = this.replaceOption(s, advsection, form.Value, 'hash_max', _('Maximum snooping table size'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'hash_max', _('Maximum snooping table size'));
o.placeholder = '512';
o.datatype = 'uinteger';
o.depends({ type: 'bridge', igmp_snooping: '1' });
- o = this.replaceOption(s, advsection, form.Flag, 'multicast_querier', _('Enable multicast querier'));
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'multicast_querier', _('Enable multicast querier'));
o.defaults = { '1': [{'igmp_snooping': '1'}], '0': [{'igmp_snooping': '0'}] };
o.depends('type', 'bridge');
- o = this.replaceOption(s, advsection, form.Value, 'robustness', _('Robustness'), _('The robustness value allows tuning for the expected packet loss on the network. If a network is expected to be lossy, the robustness value may be increased. IGMP is robust to (Robustness-1) packet losses'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'robustness', _('Robustness'), _('The robustness value allows tuning for the expected packet loss on the network. If a network is expected to be lossy, the robustness value may be increased. IGMP is robust to (Robustness-1) packet losses'));
o.placeholder = '2';
o.datatype = 'min(1)';
o.depends({ type: 'bridge', multicast_querier: '1' });
- o = this.replaceOption(s, advsection, form.Value, 'query_interval', _('Query interval'), _('Interval in centiseconds between multicast general queries. By varying the value, an administrator may tune the number of IGMP messages on the subnet; larger values cause IGMP Queries to be sent less often'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'query_interval', _('Query interval'), _('Interval in centiseconds between multicast general queries. By varying the value, an administrator may tune the number of IGMP messages on the subnet; larger values cause IGMP Queries to be sent less often'));
o.placeholder = '12500';
o.datatype = 'uinteger';
o.depends({ type: 'bridge', multicast_querier: '1' });
- o = this.replaceOption(s, advsection, form.Value, 'query_response_interval', _('Query response interval'), _('The max response time in centiseconds inserted into the periodic general queries. By varying the value, an administrator may tune the burstiness of IGMP messages on the subnet; larger values make the traffic less bursty, as host responses are spread out over a larger interval'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'query_response_interval', _('Query response interval'), _('The max response time in centiseconds inserted into the periodic general queries. By varying the value, an administrator may tune the burstiness of IGMP messages on the subnet; larger values make the traffic less bursty, as host responses are spread out over a larger interval'));
o.placeholder = '1000';
o.datatype = 'uinteger';
o.validate = function(section_id, value) {
@@ -694,24 +608,26 @@ return baseclass.extend({
};
o.depends({ type: 'bridge', multicast_querier: '1' });
- o = this.replaceOption(s, advsection, form.Value, 'last_member_interval', _('Last member interval'), _('The max response time in centiseconds inserted into group-specific queries sent in response to leave group messages. It is also the amount of time between group-specific query messages. This value may be tuned to modify the "leave latency" of the network. A reduced value results in reduced time to detect the loss of the last member of a group'));
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'last_member_interval', _('Last member interval'), _('The max response time in centiseconds inserted into group-specific queries sent in response to leave group messages. It is also the amount of time between group-specific query messages. This value may be tuned to modify the "leave latency" of the network. A reduced value results in reduced time to detect the loss of the last member of a group'));
o.placeholder = '100';
o.datatype = 'uinteger';
o.depends({ type: 'bridge', multicast_querier: '1' });
- o = this.addOption(s, gensection, form.Value, 'mtu', _('MTU'));
- o.placeholder = getDeviceValue(ifc || dev, 'getMTU');
+ o = this.addOption(s, 'devgeneral', form.Value, 'mtu', _('MTU'));
+ o.placeholder = getDeviceValue(dev, 'getMTU');
o.datatype = 'max(9200)';
- o.depends(simpledep);
+ o.depends('type', '');
+ o.depends('type', 'bridge');
- o = this.addOption(s, gensection, form.Value, 'macaddr', _('MAC address'));
- o.placeholder = getDeviceValue(ifc || dev, 'getMAC');
+ o = this.addOption(s, 'devgeneral', form.Value, 'macaddr', _('MAC address'));
+ o.placeholder = getDeviceValue(dev, 'getMAC');
o.datatype = 'macaddr';
- o.depends(simpledep);
+ o.depends('type', '');
+ o.depends('type', 'bridge');
o.depends('type', 'macvlan');
o.depends('type', 'veth');
- o = this.addOption(s, gensection, form.Value, 'peer_name', _('Peer device name'));
+ o = this.addOption(s, 'devgeneral', form.Value, 'peer_name', _('Peer device name'));
o.rmempty = true;
o.datatype = 'maxlength(15)';
o.depends('type', 'veth');
@@ -730,21 +646,21 @@ return baseclass.extend({
return form.Value.prototype.load.apply(this, arguments);
};
- o = this.addOption(s, gensection, form.Value, 'peer_macaddr', _('Peer MAC address'));
+ o = this.addOption(s, 'devgeneral', form.Value, 'peer_macaddr', _('Peer MAC address'));
o.rmempty = true;
o.datatype = 'macaddr';
o.depends('type', 'veth');
- o = this.addOption(s, gensection, form.Value, 'txqueuelen', _('TX queue length'));
+ o = this.addOption(s, 'devgeneral', form.Value, 'txqueuelen', _('TX queue length'));
o.placeholder = dev ? dev._devstate('qlen') : '';
o.datatype = 'uinteger';
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.Flag, 'promisc', _('Enable promiscious mode'));
+ o = this.addOption(s, 'devadvanced', form.Flag, 'promisc', _('Enable promiscious mode'));
o.default = o.disabled;
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.ListValue, 'rpfilter', _('Reverse path filter'));
+ o = this.addOption(s, 'devadvanced', form.ListValue, 'rpfilter', _('Reverse path filter'));
o.default = '';
o.value('', _('disabled'));
o.value('loose', _('Loose filtering'));
@@ -765,96 +681,96 @@ return baseclass.extend({
return '';
}
};
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.Flag, 'acceptlocal', _('Accept local'), _('Accept packets with local source addresses'));
+ o = this.addOption(s, 'devadvanced', form.Flag, 'acceptlocal', _('Accept local'), _('Accept packets with local source addresses'));
o.default = o.disabled;
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.Flag, 'sendredirects', _('Send ICMP redirects'));
+ o = this.addOption(s, 'devadvanced', form.Flag, 'sendredirects', _('Send ICMP redirects'));
o.default = o.enabled;
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.Value, 'neighreachabletime', _('Neighbour cache validity'), _('Time in milliseconds'));
+ o = this.addOption(s, 'devadvanced', form.Value, 'neighreachabletime', _('Neighbour cache validity'), _('Time in milliseconds'));
o.placeholder = '30000';
o.datatype = 'uinteger';
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.Value, 'neighgcstaletime', _('Stale neighbour cache timeout'), _('Timeout in seconds'));
+ o = this.addOption(s, 'devadvanced', form.Value, 'neighgcstaletime', _('Stale neighbour cache timeout'), _('Timeout in seconds'));
o.placeholder = '60';
o.datatype = 'uinteger';
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.Value, 'neighlocktime', _('Minimum ARP validity time'), _('Minimum required time in seconds before an ARP entry may be replaced. Prevents ARP cache thrashing.'));
+ o = this.addOption(s, 'devadvanced', form.Value, 'neighlocktime', _('Minimum ARP validity time'), _('Minimum required time in seconds before an ARP entry may be replaced. Prevents ARP cache thrashing.'));
o.placeholder = '0';
o.datatype = 'uinteger';
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, gensection, form.Flag, 'ipv6', _('Enable IPv6'));
+ o = this.addOption(s, 'devgeneral', form.Flag, 'ipv6', _('Enable IPv6'));
o.migrate = false;
o.default = o.enabled;
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, gensection, form.Value, 'mtu6', _('IPv6 MTU'));
- o.placeholder = getDeviceValue(ifc || dev, 'getMTU');
+ o = this.addOption(s, 'devgeneral', form.Value, 'mtu6', _('IPv6 MTU'));
+ o.placeholder = getDeviceValue(dev, 'getMTU');
o.datatype = 'max(9200)';
- o.depends(Object.assign({ ipv6: '1' }, simpledep));
+ o.depends(Object.assign({ ipv6: '1' }, 'type', ''));
- o = this.addOption(s, gensection, form.Value, 'dadtransmits', _('DAD transmits'), _('Amount of Duplicate Address Detection probes to send'));
+ o = this.addOption(s, 'devgeneral', form.Value, 'dadtransmits', _('DAD transmits'), _('Amount of Duplicate Address Detection probes to send'));
o.placeholder = '1';
o.datatype = 'uinteger';
- o.depends(Object.assign({ ipv6: '1' }, simpledep));
+ o.depends(Object.assign({ ipv6: '1' }, 'type', ''));
- o = this.addOption(s, advsection, form.Flag, 'multicast', _('Enable multicast support'));
+ o = this.addOption(s, 'devadvanced', form.Flag, 'multicast', _('Enable multicast support'));
o.default = o.enabled;
- o.depends(simpledep);
+ o.depends('type', '');
- o = this.addOption(s, advsection, form.ListValue, 'igmpversion', _('Force IGMP version'));
+ o = this.addOption(s, 'devadvanced', form.ListValue, 'igmpversion', _('Force IGMP version'));
o.value('', _('No enforcement'));
o.value('1', _('Enforce IGMPv1'));
o.value('2', _('Enforce IGMPv2'));
o.value('3', _('Enforce IGMPv3'));
- o.depends(Object.assign({ multicast: '1' }, simpledep));
+ o.depends(Object.assign({ multicast: '1' }, 'type', ''));
- o = this.addOption(s, advsection, form.ListValue, 'mldversion', _('Force MLD version'));
+ o = this.addOption(s, 'devadvanced', form.ListValue, 'mldversion', _('Force MLD version'));
o.value('', _('No enforcement'));
o.value('1', _('Enforce MLD version 1'));
o.value('2', _('Enforce MLD version 2'));
- o.depends(Object.assign({ multicast: '1' }, simpledep));
+ o.depends(Object.assign({ multicast: '1' }, 'type', ''));
if (isBridgePort(dev)) {
o = this.addOption(s, 'brport', form.Flag, 'learning', _('Enable MAC address learning'));
o.default = o.enabled;
- o.depends(simpledep);
+ o.depends('type', '');
o = this.addOption(s, 'brport', form.Flag, 'unicast_flood', _('Enable unicast flooding'));
o.default = o.enabled;
- o.depends(simpledep);
+ o.depends('type', '');
o = this.addOption(s, 'brport', form.Flag, 'isolated', _('Port isolation'), _('Only allow communication with non-isolated bridge ports when enabled'));
o.default = o.disabled;
- o.depends(simpledep);
+ o.depends('type', '');
o = this.addOption(s, 'brport', form.ListValue, 'multicast_router', _('Multicast routing'));
o.value('', _('Never'));
o.value('1', _('Learn'));
o.value('2', _('Always'));
- o.depends(Object.assign({ multicast: '1' }, simpledep));
+ o.depends(Object.assign({ multicast: '1' }, 'type', ''));
o = this.addOption(s, 'brport', form.Flag, 'multicast_to_unicast', _('Multicast to unicast'), _('Forward multicast packets as unicast packets on this device.'));
o.default = o.disabled;
- o.depends(Object.assign({ multicast: '1' }, simpledep));
+ o.depends(Object.assign({ multicast: '1' }, 'type', ''));
o = this.addOption(s, 'brport', form.Flag, 'multicast_fast_leave', _('Enable multicast fast leave'));
o.default = o.disabled;
- o.depends(Object.assign({ multicast: '1' }, simpledep));
+ o.depends(Object.assign({ multicast: '1' }, 'type', ''));
}
o = this.addOption(s, 'bridgevlan', form.Flag, 'vlan_filtering', _('Enable VLAN filterering'));
o.depends('type', 'bridge');
o.updateDefaultValue = function(section_id) {
- var device = isIface ? 'br-%s'.format(s.section) : uci.get('network', s.section, 'name'),
+ var device = uci.get('network', s.section, 'name'),
uielem = this.getUIElement(section_id),
has_vlans = false;
@@ -896,7 +812,7 @@ return baseclass.extend({
};
ss.filter = function(section_id) {
- var devname = isIface ? 'br-%s'.format(s.section) : uci.get('network', s.section, 'name');
+ var devname = uci.get('network', s.section, 'name');
return (uci.get('network', section_id, 'device') == devname);
};
@@ -943,7 +859,7 @@ return baseclass.extend({
ss.handleAdd = function(ev) {
return s.parse().then(L.bind(function() {
- var device = isIface ? 'br-%s'.format(s.section) : uci.get('network', s.section, 'name'),
+ var device = uci.get('network', s.section, 'name'),
section_ids = this.cfgsections(),
section_id = null,
max_vlan_id = 0;
@@ -1007,38 +923,25 @@ return baseclass.extend({
o = ss.option(form.Flag, 'local', _('Local'));
o.default = o.enabled;
- /* Do not touch bridge port state from interface config if legacy
- * bridge config is disabled due to explicitely declared br-xxx
- * device section... */
- if (disableLegacyBridging)
- return;
-
var ports = [];
- if (isIface) {
- Array.prototype.push.apply(ports, L.toArray(ifc.getDevices() || ifc.getDevice()).map(function(dev) {
- return dev.getName();
- }));
- }
- else {
- var seen_ports = {};
+ var seen_ports = {};
- L.toArray(uci.get('network', s.section, 'ifname')).forEach(function(ifname) {
- seen_ports[ifname] = true;
- });
+ L.toArray(uci.get('network', s.section, 'ports')).forEach(function(port) {
+ seen_ports[port] = true;
+ });
- uci.sections('network', 'bridge-vlan', function(bvs) {
- L.toArray(bvs.ports).forEach(function(portspec) {
- var m = portspec.match(/^([^:]+)(?::[ut*]+)?$/);
+ uci.sections('network', 'bridge-vlan', function(bvs) {
+ L.toArray(bvs.ports).forEach(function(portspec) {
+ var m = portspec.match(/^([^:]+)(?::[ut*]+)?$/);
- if (m)
- seen_ports[m[1]] = true;
- });
+ if (m)
+ seen_ports[m[1]] = true;
});
+ });
- for (var port_name in seen_ports)
- ports.push(port_name);
- }
+ for (var port_name in seen_ports)
+ ports.push(port_name);
ports.sort();
diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
index 253b37b846..0d1420772e 100644
--- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
+++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
@@ -450,7 +450,11 @@ return view.extend({
node.addEventListener('cbi-dropdown-change', L.bind(function(ipopt, section_id, ev) {
var mac = ev.detail.value.value;
- if (mac == null || mac == '' || !hosts[mac] || !hosts[mac].ipv4)
+ if (mac == null || mac == '' || !hosts[mac])
+ return;
+
+ var iphint = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0];
+ if (iphint == null)
return;
var ip = ipopt.formvalue(section_id);
@@ -459,13 +463,13 @@ return view.extend({
var node = ipopt.map.findElement('id', ipopt.cbid(section_id));
if (node)
- dom.callClassMethod(node, 'setValue', hosts[mac].ipv4);
+ dom.callClassMethod(node, 'setValue', iphint);
}, this, ipopt, section_id));
return node;
};
Object.keys(hosts).forEach(function(mac) {
- var hint = hosts[mac].name || hosts[mac].ipv4;
+ var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0];
so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac);
});
@@ -501,11 +505,18 @@ return view.extend({
return true;
};
+
+ var ipaddrs = {};
+
Object.keys(hosts).forEach(function(mac) {
- if (hosts[mac].ipv4) {
- var hint = hosts[mac].name;
- so.value(hosts[mac].ipv4, hint ? '%s (%s)'.format(hosts[mac].ipv4, hint) : hosts[mac].ipv4);
- }
+ var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4);
+
+ for (var i = 0; i < addrs.length; i++)
+ ipaddrs[addrs[i]] = hosts[mac].name;
+ });
+
+ L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) {
+ so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4);
});
so = ss.option(form.Value, 'leasetime', _('Lease time'));
@@ -563,7 +574,7 @@ return view.extend({
exp = '%t'.format(lease.expires);
var hint = lease.macaddr ? hosts[lease.macaddr] : null,
- name = hint ? (hint.name || hint.ipv4 || hint.ipv6) : null,
+ name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null,
host = null;
if (name && lease.hostname && lease.hostname != name && lease.ip6addr != name)
diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
index cd0dacbf67..93ebf5ba68 100644
--- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
+++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
@@ -31,11 +31,18 @@ return view.extend({
o = s.option(form.Value, 'ip', _('IP address'));
o.datatype = 'ipaddr';
o.rmempty = true;
- L.sortedKeys(hosts, 'ipv4', 'addr').forEach(function(mac) {
- o.value(hosts[mac].ipv4, '%s (%s)'.format(
- hosts[mac].ipv4,
- hosts[mac].name || mac
- ));
+
+ var ipaddrs = {};
+
+ Object.keys(hosts).forEach(function(mac) {
+ var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4);
+
+ for (var i = 0; i < addrs.length; i++)
+ ipaddrs[addrs[i]] = hosts[mac].name || mac;
+ });
+
+ L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) {
+ o.value(ipv4, '%s (%s)'.format(ipv4, ipaddrs[ipv4]));
});
return m.render();
diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
index 4a2e94faf6..544cad1aa1 100644
--- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
+++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
@@ -294,11 +294,111 @@ return view.extend({
network.getDSLModemType(),
network.getDevices(),
fs.lines('/etc/iproute2/rt_tables'),
+ L.resolveDefault(fs.read('/usr/lib/opkg/info/netifd.control')),
uci.changes()
]);
},
+ interfaceBridgeWithIfnameSections: function() {
+ return uci.sections('network', 'interface').filter(function(ns) {
+ return ns.type == 'bridge' && !ns.ports && ns.ifname;
+ });
+ },
+
+ deviceWithIfnameSections: function() {
+ return uci.sections('network', 'device').filter(function(ns) {
+ return ns.type == 'bridge' && !ns.ports && ns.ifname;
+ });
+ },
+
+ interfaceWithIfnameSections: function() {
+ return uci.sections('network', 'interface').filter(function(ns) {
+ return !ns.device && ns.ifname;
+ });
+ },
+
+ handleBridgeMigration: function(ev) {
+ var tasks = [];
+
+ this.interfaceBridgeWithIfnameSections().forEach(function(ns) {
+ var device_name = 'br-' + ns['.name'];
+
+ tasks.push(uci.callAdd('network', 'device', null, {
+ 'name': device_name,
+ 'type': 'bridge',
+ 'ports': L.toArray(ns.ifname),
+ 'macaddr': ns.macaddr
+ }));
+
+ tasks.push(uci.callSet('network', ns['.name'], {
+ 'type': '',
+ 'ifname': '',
+ 'macaddr': '',
+ 'device': device_name
+ }));
+ });
+
+ return Promise.all(tasks)
+ .then(L.bind(ui.changes.init, ui.changes))
+ .then(L.bind(ui.changes.apply, ui.changes));
+ },
+
+ renderBridgeMigration: function() {
+ ui.showModal(_('Network bridge configuration migration'), [
+ E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')),
+ E('p', _('Upon pressing "Continue", bridges configuration will be updated and the network will be restarted to apply the updated configuration.')),
+ E('div', { 'class': 'right' },
+ E('button', {
+ 'class': 'btn cbi-button-action important',
+ 'click': ui.createHandlerFn(this, 'handleBridgeMigration')
+ }, _('Continue')))
+ ]);
+ },
+
+ handleIfnameMigration: function(ev) {
+ var tasks = [];
+
+ this.deviceWithIfnameSections().forEach(function(ds) {
+ tasks.push(uci.add('network', ds['.name'], {
+ 'ifname': '',
+ 'ports': L.toArray(ds.ifname)
+ }));
+ });
+
+ this.interfaceWithIfnameSections().forEach(function(ns) {
+ tasks.push(uci.callSet('network', ns['.name'], {
+ 'ifname': '',
+ 'device': ns.ifname
+ }));
+ });
+
+ return Promise.all(tasks)
+ .then(L.bind(ui.changes.init, ui.changes))
+ .then(L.bind(ui.changes.apply, ui.changes));
+ },
+
+ renderIfnameMigration: function() {
+ ui.showModal(_('Network ifname configuration migration'), [
+ E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')),
+ E('p', _('Upon pressing "Continue", ifname options will get renamed and the network will be restarted to apply the updated configuration.')),
+ E('div', { 'class': 'right' },
+ E('button', {
+ 'class': 'btn cbi-button-action important',
+ 'click': ui.createHandlerFn(this, 'handleIfnameMigration')
+ }, _('Continue')))
+ ]);
+ },
+
render: function(data) {
+ var netifdVersion = (data[3] || '').match(/Version: ([^\n]+)/);
+
+ if (netifdVersion && netifdVersion[1] >= "2021-05-26") {
+ if (this.interfaceBridgeWithIfnameSections().length)
+ return this.renderBridgeMigration();
+ else if (this.deviceWithIfnameSections().length || this.interfaceWithIfnameSections().length)
+ return this.renderIfnameMigration();
+ }
+
var dslModemType = data[0],
netDevs = data[1],
m, s, o;
@@ -381,7 +481,7 @@ return view.extend({
s.addModalOptions = function(s) {
var protoval = uci.get('network', s.section, 'proto'),
protoclass = protoval ? network.getProtocol(protoval) : null,
- o, ifname_single, ifname_multi, proto_select, proto_switch, type, stp, igmp, ss, so;
+ o, proto_select, proto_switch, type, stp, igmp, ss, so;
if (!protoval)
return;
@@ -405,6 +505,7 @@ return view.extend({
}, this);
o.write = function() {};
+
proto_select = s.taboption('general', form.ListValue, 'proto', _('Protocol'));
proto_select.modalonly = true;
@@ -420,6 +521,12 @@ return view.extend({
.then(L.bind(this.renderMoreOptionsModal, this, s.section));
}, this);
+ o = s.taboption('general', widgets.DeviceSelect, '_net_device', _('Device'));
+ o.ucioption = 'device';
+ o.nobridges = false;
+ o.optional = false;
+ o.network = ifc.getName();
+
o = s.taboption('general', form.Flag, 'auto', _('Bring up on boot'));
o.modalonly = true;
o.default = o.enabled;
@@ -568,7 +675,7 @@ return view.extend({
so = ss.taboption('ipv6', form.Value, 'ra_maxinterval', _('Max <abbr title="Router Advertisement">RA</abbr> interval'), _('Maximum time allowed \
between sending unsolicited <abbr title="Router Advertisement, ICMPv6 Type 134">RA</abbr>. Default is 600 seconds (<code>600</code>).'));
so.optional = true;
- so.default = '600';
+ so.placeholder = '600';
so.depends('ra', 'server');
so.depends('ra', 'hybrid');
so.depends('ra', 'relay');
@@ -577,7 +684,7 @@ return view.extend({
so = ss.taboption('ipv6', form.Value, 'ra_mininterval', _('Min <abbr title="Router Advertisement">RA</abbr> interval'), _('Minimum time allowed \
between sending unsolicited <abbr title="Router Advertisement, ICMPv6 Type 134">RA</abbr>. Default is 200 seconds (<code>200</code>).'));
so.optional = true;
- so.default = '200';
+ so.placeholder = '200';
so.depends('ra', 'server');
so.depends('ra', 'hybrid');
so.depends('ra', 'relay');
@@ -586,7 +693,6 @@ return view.extend({
in <abbr title="Router Advertisement, ICMPv6 Type 134">RA</abbr> messages. Default is 1800 seconds (<code>1800</code>). \
Max 9000 seconds.'));
so.optional = true;
- so.default = '1800';
so.depends('ra', 'server');
so.depends('ra', 'hybrid');
so.depends('ra', 'relay');
@@ -595,7 +701,6 @@ return view.extend({
to be published in <abbr title="Router Advertisement, ICMPv6 Type 134">RA</abbr> messages. Default is 0 (<code>0</code>).\
Min 1280.'));
so.optional = true;
- so.default = '0';
so.depends('ra', 'server');
so.depends('ra', 'hybrid');
so.depends('ra', 'relay');
@@ -604,7 +709,6 @@ return view.extend({
to be published in <abbr title="Router Advertisement">RA</abbr> messages.<br />Default is 0 (<code>0</code>), meaning unspecified.\
Max 255.'));
so.optional = true;
- so.default = '0';
so.depends('ra', 'server');
so.depends('ra', 'hybrid');
so.depends('ra', 'relay');
@@ -657,6 +761,7 @@ return view.extend({
so = ss.taboption('ipv6', form.Flag, 'ndproxy_routing', _('Learn routes from NDP'), _('Default is on.'));
so.default = '1';
+ so.optional = true;
so = ss.taboption('ipv6', form.Flag, 'ndproxy_slave', _('NDP-Proxy slave'), _('Set interface as NDP-Proxy external slave. Default is off.'));
@@ -666,10 +771,6 @@ return view.extend({
so.depends('dhcpv6', 'relay');
so.depends('dhcpv6', 'hybrid');
- so = ss.taboption('ipv6', form.Flag , 'master', _('Master'), _('Set this interface as master for the dhcpv6 relay.'));
- so.depends('dhcpv6', 'relay');
- so.depends('dhcpv6', 'hybrid');
-
so = ss.taboption('ipv6', form.Flag, 'ra_default', _('Announce as default router'), _('Always, even if no public prefix is available.'));
so.depends('ra', 'server');
so.depends('ra', 'hybrid');
@@ -679,7 +780,6 @@ return view.extend({
}
ifc.renderFormOptions(s);
- nettools.addDeviceOptions(s, null, true);
// Common interface options
o = nettools.replaceOption(s, 'advanced', form.Flag, 'defaultroute', _('Use default gateway'), _('If unchecked, no default route is configured'));
@@ -786,11 +886,10 @@ return view.extend({
case '_ifacestat_modal':
continue;
- case 'ifname_multi':
- case 'ifname_single':
case 'igmp_snooping':
case 'stp':
case 'type':
+ case '_net_device':
var deps = [];
for (var j = 0; j < protocols.length; j++) {
if (!protocols[j].isVirtual()) {
@@ -819,10 +918,10 @@ return view.extend({
s.handleModalCancel = function(/* ... */) {
var type = uci.get('network', this.activeSection || this.addedSection, 'type'),
- ifname = (type == 'bridge') ? 'br-%s'.format(this.activeSection || this.addedSection) : null;
+ device = (type == 'bridge') ? 'br-%s'.format(this.activeSection || this.addedSection) : null;
uci.sections('network', 'bridge-vlan', function(bvs) {
- if (ifname != null && bvs.device == ifname)
+ if (device != null && bvs.device == device)
uci.remove('network', bvs['.name']);
});
@@ -833,7 +932,7 @@ return view.extend({
var m2 = new form.Map('network'),
s2 = m2.section(form.NamedSection, '_new_'),
protocols = network.getProtocols(),
- proto, name, bridge, ifname_single, ifname_multi;
+ proto, name, device;
protocols.sort(function(a, b) {
return a.getProtocol() > b.getProtocol();
@@ -866,30 +965,15 @@ return view.extend({
proto = s2.option(form.ListValue, 'proto', _('Protocol'));
proto.validate = name.validate;
- bridge = s2.option(form.Flag, 'type', _('Bridge interfaces'), _('Creates a bridge over specified interface(s)'));
- bridge.modalonly = true;
- bridge.disabled = '';
- bridge.enabled = 'bridge';
-
- ifname_single = s2.option(widgets.DeviceSelect, 'ifname_single', _('Interface'));
- ifname_single.noaliases = false;
- ifname_single.optional = false;
-
- ifname_multi = s2.option(widgets.DeviceSelect, 'ifname_multi', _('Interface'));
- ifname_multi.nobridges = true;
- ifname_multi.noaliases = true;
- ifname_multi.multiple = true;
- ifname_multi.optional = true;
- ifname_multi.display_size = 6;
+ device = s2.option(widgets.DeviceSelect, 'device', _('Device'));
+ device.noaliases = false;
+ device.optional = false;
for (var i = 0; i < protocols.length; i++) {
proto.value(protocols[i].getProtocol(), protocols[i].getI18n());
- if (!protocols[i].isVirtual()) {
- bridge.depends({ proto: protocols[i].getProtocol() });
- ifname_single.depends({ type: '', proto: protocols[i].getProtocol() });
- ifname_multi.depends({ type: 'bridge', proto: protocols[i].getProtocol() });
- }
+ if (!protocols[i].isVirtual())
+ device.depends('proto', protocols[i].getProtocol());
}
m2.render().then(L.bind(function(nodes) {
@@ -922,16 +1006,7 @@ return view.extend({
var section_id = uci.add('network', 'interface', nameval);
protoclass.set('proto', protoval);
-
- if (ifname_single.isActive('_new_')) {
- protoclass.addDevice(ifname_single.formvalue('_new_'));
- }
- else if (ifname_multi.isActive('_new_')) {
- protoclass.set('type', 'bridge');
- L.toArray(ifname_multi.formvalue('_new_')).map(function(dev) {
- protoclass.addDevice(dev);
- });
- }
+ protoclass.addDevice(device.formvalue('_new_'));
m.children[0].addedSection = section_id;
}).then(L.bind(m.children[0].renderMoreOptionsModal, m.children[0], nameval));
@@ -1049,6 +1124,18 @@ return view.extend({
if (m) {
var devtype = getDevType(section_id);
+ /* Treat not explicitly configured, preexisting VLAN interfaces
+ as simple network devices when adding configuration for them,
+ since it is more likely that people want to set general device
+ properties such as MAC address instead of reconfiguring ingress/
+ egress QoS mapping, which is the only editable property of
+ preexisting VLAN device config dialogs.
+
+ Ref: https://github.com/openwrt/luci/issues/5102
+ */
+ if (devtype == '8021q')
+ devtype = 'ethernet';
+
section_id = uci.add('network', 'device');
uci.set('network', section_id, 'name', m[1]);
@@ -1065,6 +1152,7 @@ return view.extend({
deleteBtn = trEl.querySelector('button:last-child');
deleteBtn.firstChild.data = _('Reset');
+ deleteBtn.setAttribute('title', _('Remove related device settings from the configuration'));
deleteBtn.disabled = section_id.match(/^dev:/) ? true : null;
return trEl;
@@ -1103,10 +1191,11 @@ return view.extend({
}
function getDevType(section_id) {
- var cfgtype = uci.get('network', section_id, 'type'),
- dev = getDevice(section_id);
+ var dev = getDevice(section_id),
+ cfg = uci.get('network', section_id),
+ type = cfg ? (uci.get('network', section_id, 'type') || 'ethernet') : (dev ? dev.getType() : '');
- switch (cfgtype || (dev ? dev.getType() : '')) {
+ switch (type) {
case '':
return null;