diff --git a/dsvpn/files/init b/dsvpn/files/init
index 250c409df..1d78ed4be 100755
--- a/dsvpn/files/init
+++ b/dsvpn/files/init
@@ -49,7 +49,7 @@ start_instance() {
key=""
if [ "$(uci -q get network.omrvpn)" != "" ] && [ "$(uci -q get network.omrvpn)" != "$dev" ]; then
- uci -q set network.omrvpn.ifname=$dev
+ uci -q set network.omrvpn.device=$dev
uci -q commit
fi
diff --git a/glorytun-udp/init b/glorytun-udp/init
index e9f7caf7c..f5086024f 100755
--- a/glorytun-udp/init
+++ b/glorytun-udp/init
@@ -50,7 +50,7 @@ start_instance() {
key=""
if [ "$(uci -q get network.omrvpn)" != "" ]; then
- uci -q set network.omrvpn.ifname=$dev
+ uci -q set network.omrvpn.device=$dev
uci -q commit
fi
diff --git a/glorytun/init b/glorytun/init
index f5b868323..3d549f0aa 100755
--- a/glorytun/init
+++ b/glorytun/init
@@ -59,7 +59,7 @@ start_instance() {
key=""
if [ "$(uci -q get network.omrvpn)" != "" ]; then
- uci -q set network.omrvpn.ifname=${dev}
+ uci -q set network.omrvpn.device=${dev}
uci -q commit network
fi
_log "starting ${PROG_NAME} ${1} instance $*"
diff --git a/luci-app-glorytun-tcp/root/etc/uci-defaults/1200-luci-glorytun b/luci-app-glorytun-tcp/root/etc/uci-defaults/1200-luci-glorytun
index 9d0f93d85..e78973fe0 100644
--- a/luci-app-glorytun-tcp/root/etc/uci-defaults/1200-luci-glorytun
+++ b/luci-app-glorytun-tcp/root/etc/uci-defaults/1200-luci-glorytun
@@ -15,7 +15,7 @@ if [ "$(uci -q get network.glorytun)" = "" ] && [ "$(uci -q get network.omrvpn)"
uci -q batch <<-EOF >/dev/null
delete network.glorytun
set network.glorytun=interface
- set network.glorytun.ifname=tun0
+ set network.glorytun.device=tun0
set network.glorytun.proto=dhcp
set network.glorytun.ip4table=vpn
set network.glorytun.multipath=off
@@ -48,6 +48,7 @@ if [ "$(uci -q show firewall | grep Allow-All-LAN-to-VPN)" = "" ]; then
set firewall.@rule[-1].name='Allow-All-LAN-to-VPN'
set firewall.@rule[-1].dest='vpn'
set firewall.@rule[-1].src='lan'
+ set firewall.@rule[-1].proto='all'
commit firewall
EOF
fi
diff --git a/luci-app-glorytun-udp/root/etc/uci-defaults/1201-luci-glorytun-udp b/luci-app-glorytun-udp/root/etc/uci-defaults/1201-luci-glorytun-udp
index dbecf5b5b..ebe335318 100644
--- a/luci-app-glorytun-udp/root/etc/uci-defaults/1201-luci-glorytun-udp
+++ b/luci-app-glorytun-udp/root/etc/uci-defaults/1201-luci-glorytun-udp
@@ -11,7 +11,7 @@ if [ "$(uci -q get network.glorytun-udp)" = "" ] && [ "$(uci -q get network.omrv
uci -q batch <<-EOF >/dev/null
delete network.glorytun-udp
set network.glorytun-udp=interface
- set network.glorytun-udp.ifname=tun0
+ set network.glorytun-udp.device=tun0
set network.glorytun-udp.proto=dhcp
set network.glorytun-udp.ip4table=vpn
set network.glorytun-udp.multipath=off
diff --git a/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua b/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua
index 3d243b210..cca82d950 100644
--- a/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua
+++ b/luci-app-openmptcprouter/luasrc/controller/openmptcprouter.lua
@@ -26,7 +26,11 @@ end
function interface_from_device(dev)
for _, iface in ipairs(net:get_networks()) do
local ifacen = iface:name()
- local ifacename = ucic:get("network",ifacen,"ifname")
+ local ifacename = ""
+ ifacename = ucic:get("network",ifacen,"device")
+ if ifacename == "" then
+ ifacename = ucic:get("network",ifacen,"ifname")
+ end
if ifacename == dev then
return ifacen
end
@@ -113,7 +117,10 @@ function wizard_add()
end)
local defif = "eth0"
if add_interface_ifname == "" then
- local defif1 = ucic:get("network","wan1_dev","ifname") or ""
+ local defif1 = ucic:get("network","wan1_dev","device") or ""
+ if defif1 == "" then
+ defif1 = ucic:get("network","wan1_dev","ifname") or ""
+ end
if defif1 ~= "" then
defif = defif1
end
@@ -126,17 +133,29 @@ function wizard_add()
if ointf ~= "" then
if ucic:get("network",ointf,"type") == "" then
ucic:set("network",ointf,"type","macvlan")
+ ucic:set("network",ointf,"device",ointf)
+ ucic:set("network",ointf .. "_dev","device")
+ ucic:set("network",ointf .. "_dev","type","macvlan")
+ ucic:set("network",ointf .. "_dev","mode","vepa")
+ ucic:set("network",ointf .. "_dev","ifname",defif)
+ ucic:set("network",ointf .. "_dev","name",ointf)
end
wanif = "wan" .. i
end
ucic:set("network","wan" .. i,"interface")
- ucic:set("network","wan" .. i,"ifname",defif)
+ ucic:set("network","wan" .. i,"device",defif)
ucic:set("network","wan" .. i,"proto","static")
ucic:set("openmptcprouter","wan" .. i,"interface")
if ointf ~= "" then
ucic:set("network","wan" .. i,"type","macvlan")
+ ucic:set("network","wan" .. i,"device","wan" .. i)
ucic:set("network","wan" .. i,"masterintf",defif)
+ ucic:set("network","wan" .. i .. "_dev","device")
+ ucic:set("network","wan" .. i .. "_dev","type","macvlan")
+ ucic:set("network","wan" .. i .. "_dev","mode","vepa")
+ ucic:set("network","wan" .. i .. "_dev","ifname",defif)
+ ucic:set("network","wan" .. i .. "_dev","name","wan" .. i)
end
ucic:set("network","wan" .. i,"ip4table","wan")
if multipath_master then
@@ -197,7 +216,10 @@ function wizard_add()
local delete_intf = luci.http.formvaluetable("delete") or ""
if delete_intf ~= "" then
for intf, _ in pairs(delete_intf) do
- local defif = ucic:get("network",intf,"ifname")
+ local defif = ucic:get("network",intf,"ifname") or ""
+ if defif == "" then
+ defif = ucic:get("network",intf,"ifname")
+ end
ucic:delete("network",intf)
if ucic:get("network",intf .. "_dev") ~= "" then
ucic:delete("network",intf .. "_dev")
@@ -262,9 +284,14 @@ function wizard_add()
end
if typeintf == "macvlan" and masterintf ~= "" then
ucic:set("network",intf,"type","macvlan")
+ ucic:set("network",intf .. "_dev","device")
+ ucic:set("network",intf .. "_dev","type","macvlan")
+ ucic:set("network",intf .. "_dev","ifname",masterinf)
+ ucic:set("network",intf .. "_dev","mode","vepa")
+ ucic:set("network",intf .. "_dev","name",intf)
ucic:set("network",intf,"masterintf",masterintf)
elseif typeintf == "" and ifname ~= "" and (proto == "static" or proto == "dhcp" or proto == "dhcpv6") then
- ucic:set("network",intf,"ifname",ifname)
+ ucic:set("network",intf,"device",ifname)
elseif typeintf == "" and device ~= "" and proto == "ncm" then
ucic:set("network",intf,"device",device_ncm)
elseif typeintf == "" and device ~= "" and proto == "qmi" then
@@ -342,7 +369,10 @@ function wizard_add()
if not ucic:get("sqm",intf) ~= "" then
local defif = get_device(intf)
if defif == "" then
- defif = ucic:get("network",intf,"ifname") or ""
+ defif = ucic:get("network",intf,"device") or ""
+ if defif == "" then
+ defif = ucic:get("network",intf,"ifname") or ""
+ end
end
ucic:set("sqm",intf,"queue")
ucic:set("sqm",intf,"interface",defif)
@@ -442,7 +472,7 @@ function wizard_add()
ucic:set("network","omrvpn","proto","bonding")
end
if vpn_intf ~= "" then
- ucic:set("network","omrvpn","ifname",vpn_intf)
+ ucic:set("network","omrvpn","device",vpn_intf)
ucic:set("sqm","omrvpn","interface",vpn_intf)
ucic:save("network")
ucic:commit("network")
@@ -894,7 +924,7 @@ function wizard_add()
-- Restart all
menuentry = ucic:get("openmptcprouter","settings","menu") or "openmptcprouter"
if gostatus == true then
- luci.sys.call("/etc/init.d/macvlan restart >/dev/null 2>/dev/null")
+ --luci.sys.call("/etc/init.d/macvlan restart >/dev/null 2>/dev/null")
luci.sys.call("(env -i /bin/ubus call network reload) >/dev/null 2>/dev/null")
luci.sys.call("ip addr flush dev tun0 >/dev/null 2>/dev/null")
luci.sys.call("/etc/init.d/omr-tracker stop >/dev/null 2>/dev/null")
diff --git a/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm b/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm
index 9c39c3c33..c6db8b9e5 100644
--- a/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm
+++ b/luci-app-openmptcprouter/luasrc/view/openmptcprouter/wizard.htm
@@ -473,7 +473,7 @@
if not (ifacea == "lo" or ifacea == "6in4-omr6in4" or ifacea == "mlvpn0" or ifacea:match("^ifb.*") or ifacea:match("^sit.*") or ifacea:match("^gre.*") or ifacea:match("^ip6.*") or ifacea:match("^teql.*") or ifacea:match("^erspan.*") or ifacea:match("^tun.*") or ifacea:match("^bond.*")) and device_notvirtual(ifacea) then
if uci:get("network",ifname,"proto") ~= "macvlan" then
%>
- selected="selected"<% end %>><%=ifacea%>
+ selected="selected"<% end %>><%=ifacea%>
<%
else
%>
@@ -483,9 +483,9 @@
end
end
if uci:get("network",ifname,"proto") ~= "macvlan" then
- if iffind == 0 and uci:get("network",ifname,"ifname") ~= nil then
+ if iffind == 0 and uci:get("network",ifname,"device") ~= nil then
%>
- " selected="selected"><%=uci:get("network",ifname,"ifname")%>
+ " selected="selected"><%=uci:get("network",ifname,"device")%>
<%
end
else
@@ -616,7 +616,7 @@
<%
iffind=0
- uciifname=uci:get("network",ifname,"ifname")
+ uciifname=uci:get("network",ifname,"device")
if uciifname ~= nil then
if uciifname:match("/") then
realifname=uciifname
diff --git a/luci-app-openmptcprouter/root/etc/init.d/openmptcprouter b/luci-app-openmptcprouter/root/etc/init.d/openmptcprouter
index 9c547bff8..42ed7d1b9 100755
--- a/luci-app-openmptcprouter/root/etc/init.d/openmptcprouter
+++ b/luci-app-openmptcprouter/root/etc/init.d/openmptcprouter
@@ -18,7 +18,8 @@ omr_intf_check() {
omr_intf_set() {
local device
local ifname
- config_get ifname "$1" ifname
+ config_get ifname "$1" device
+ [ -z "$ifname" ] && config_get ifname "$1" ifname
config_get device "$1" device
config_get type "$1" type
@@ -56,7 +57,8 @@ omr_set_settings() {
local ifname
local multipath
config_get multipath "$1" multipath
- config_get ifname "$1" ifname
+ config_get ifname "$1" device
+ [ -z "$ifname" ] && config_get ifname "$1" ifname
config_get device "$1" device
config_get proto "$1" proto
config_get type "$1" type
diff --git a/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter b/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter
index effce068c..977f67372 100755
--- a/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter
+++ b/luci-app-openmptcprouter/root/usr/libexec/rpcd/openmptcprouter
@@ -11,7 +11,7 @@ local jsonc = require "luci.jsonc"
function interface_from_device(dev)
for _, iface in ipairs(net:get_networks()) do
local ifacen = iface:name()
- local ifacename = ucic:get("network",ifacen,"ifname")
+ local ifacename = ucic:get("network",ifacen,"device")
if ifacename == dev then
return ifacen
end
@@ -72,7 +72,7 @@ function add_interface(add_interface_ifname)
end
ucic:set("network","wan" .. i,"interface")
- ucic:set("network","wan" .. i,"ifname",defif)
+ ucic:set("network","wan" .. i,"device",defif)
ucic:set("network","wan" .. i,"proto","static")
if ointf ~= "" then
ucic:set("network","wan" .. i,"type","macvlan")
@@ -128,7 +128,7 @@ end
function remove_interface(intf)
-- Remove existing interface
- local defif = ucic:get("network",intf,"ifname")
+ local defif = ucic:get("network",intf,"device")
ucic:delete("network",intf)
ucic:delete("network",intf .. "_dev")
ucic:save("network")
@@ -170,7 +170,7 @@ function set_interface(intf,proto,ipaddr,netmask,gateway,sqmenabled,downloadspee
if not ucic:get("sqm",intf) ~= "" then
local defif = get_device(intf)
if defif == "" then
- defif = ucic:get("network",intf,"ifname") or ""
+ defif = ucic:get("network",intf,"device") or ""
end
ucic:set("sqm",intf,"queue")
ucic:set("sqm",intf,"interface",defif)
@@ -268,7 +268,7 @@ function default_vpn(default_vpn)
ucic:set("network","omrvpn","proto","dhcp")
end
if vpn_intf ~= "" then
- ucic:set("network","omrvpn","ifname",vpn_intf)
+ ucic:set("network","omrvpn","device",vpn_intf)
ucic:save("network")
ucic:commit("network")
end
@@ -961,7 +961,10 @@ function interfaces_status()
if string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?glorytun(-udp)?$'"), "%d+") or string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?dsvpn?$'"), "%d+") or string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?mlvpn?$'"), "%d+") or string.find(sys.exec("/usr/bin/pgrep '^(/usr/sbin/)?openvpn?$'"), "%d+") then
mArray.openmptcprouter["tun_service"] = true
mArray.openmptcprouter["tun_ip"] = get_ip("omrvpn")
- local tun_dev = uci:get("network","omrvpn","ifname")
+ local tun_dev = uci:get("network","omrvpn","device")
+ if tun_dev == "" then
+ tun_dev = uci:get("network","omrvpn","ifname")
+ end
if tun_dev == "" then
tun_dev = get_device("omrvpn")
end
@@ -1139,14 +1142,14 @@ function interfaces_status()
local ifname = get_device(interface)
if ifname == "" or ifname == nil then
- ifname = section["ifname"] or ""
+ ifname = section["device"] or ""
end
--if ifname ~= nil and ifname:match("^tun.*") and interface:match("^ovpn.*") then
--ifname = get_device(interface:sub(5))
--end
duplicateif = false
- if ifname ~= "" and ifname ~= nil and not (section["ifname"] ~= nil and section["ifname"]:match("^@.*")) then
+ if ifname ~= "" and ifname ~= nil and not (section["device"] ~= nil and section["device"]:match("^@.*")) then
if allintf[ifname] then
connectivity = "ERROR"
duplicateif = true
@@ -1156,7 +1159,7 @@ function interfaces_status()
end
duplicatemac = false
- if mac ~= "" and mac ~= nil and not (section["ifname"] ~= nil and section["ifname"]:match("^@.*")) then
+ if mac ~= "" and mac ~= nil and not (section["device"] ~= nil and section["device"]:match("^@.*")) then
if allmac[mac] then
connectivity = "ERROR"
duplicatemac = true
diff --git a/luci-mod-dashboard/htdocs/luci-static/resources/view/dashboard/include/10_router.js b/luci-mod-dashboard/htdocs/luci-static/resources/view/dashboard/include/10_router.js
index b5892cff2..ad9278c53 100644
--- a/luci-mod-dashboard/htdocs/luci-static/resources/view/dashboard/include/10_router.js
+++ b/luci-mod-dashboard/htdocs/luci-static/resources/view/dashboard/include/10_router.js
@@ -371,7 +371,7 @@ return baseclass.extend({
release: {
title: _('Firmware Version'),
- value: boardinfo.release.description ? boardinfo.release.description : null
+ value: (typeof boardinfo.release.description !== "undefined") ? boardinfo.release.description : null
}
};
diff --git a/luci-mod-network/Makefile b/luci-mod-network/Makefile
index 71e847f31..6148f98b4 100644
--- a/luci-mod-network/Makefile
+++ b/luci-mod-network/Makefile
@@ -1,10 +1,10 @@
#
# Copyright (C) 2008-2014 The LuCI Team
-# Copyright (C) 2020 Ycarus (Yannick Chabanois) for OpenMPTCProuter
+# Copyright (C) 2020-2021 Ycarus (Yannick Chabanois) for OpenMPTCProuter
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
-# From https://github.com/openwrt/luci/commit/f5c04e1a2e173f536597f220db0380cc08869e8e
+# From https://github.com/openwrt/luci/commit/b88157e69a060ade618e48b30947729310935d61
include $(TOPDIR)/rules.mk
diff --git a/luci-mod-network/htdocs/luci-static/resources/tools/network.js b/luci-mod-network/htdocs/luci-static/resources/tools/network.js
new file mode 100644
index 000000000..8efbd89d4
--- /dev/null
+++ b/luci-mod-network/htdocs/luci-static/resources/tools/network.js
@@ -0,0 +1,913 @@
+'use strict';
+'require ui';
+'require dom';
+'require uci';
+'require form';
+'require network';
+'require baseclass';
+'require validation';
+'require tools.widgets as widgets';
+
+function validateAddr(section_id, value) {
+ if (value == '')
+ return true;
+
+ var ipv6 = /6$/.test(this.section.formvalue(section_id, 'mode')),
+ addr = ipv6 ? validation.parseIPv6(value) : validation.parseIPv4(value);
+
+ return addr ? true : (ipv6 ? _('Expecting a valid IPv6 address') : _('Expecting a valid IPv4 address'));
+}
+
+function validateQoSMap(section_id, value) {
+ if (value == '')
+ return true;
+
+ var m = value.match(/^(\d+):(\d+)$/);
+
+ if (!m || +m[1] > 0xFFFFFFFF || +m[2] > 0xFFFFFFFF)
+ return _('Expecting two priority values separated by a colon');
+
+ return true;
+}
+
+function deviceSectionExists(section_id, devname) {
+ var exists = false;
+
+ uci.sections('network', 'device', function(ss) {
+ exists = exists || (
+ ss['.name'] != section_id &&
+ ss.name == devname
+ );
+ });
+
+ return exists;
+}
+
+function isBridgePort(dev) {
+ if (!dev)
+ return false;
+
+ if (dev.isBridgePort())
+ return true;
+
+ var isPort = false;
+
+ uci.sections('network', null, function(s) {
+ if (s['.type'] != 'interface' && s['.type'] != 'device')
+ return;
+
+ if (s.type == 'bridge' && L.toArray(s.ifname).indexOf(dev.getName()) > -1)
+ isPort = true;
+ });
+
+ return isPort;
+}
+
+function updateDevBadge(node, dev) {
+ var type = dev.getType(),
+ up = dev.getCarrier();
+
+ dom.content(node, [
+ E('img', {
+ 'class': 'middle',
+ 'src': L.resource('icons/%s%s.png').format(type, up ? '' : '_disabled')
+ }),
+ '\x0a', dev.getName()
+ ]);
+
+ return node;
+}
+
+function renderDevBadge(dev) {
+ return updateDevBadge(E('span', {
+ 'class': 'ifacebadge port-status-device',
+ 'style': 'font-weight:normal',
+ 'data-device': dev.getName()
+ }), dev);
+}
+
+function updatePortStatus(node, dev) {
+ var carrier = dev.getCarrier(),
+ duplex = dev.getDuplex(),
+ speed = dev.getSpeed(),
+ desc, title;
+
+ if (carrier && speed > 0 && duplex != null) {
+ desc = '%d%s'.format(speed, duplex == 'full' ? 'FD' : 'HD');
+ title = '%s, %d MBit/s, %s'.format(_('Connected'), speed, duplex == 'full' ? _('full-duplex') : _('half-duplex'));
+ }
+ else if (carrier) {
+ desc = _('Connected');
+ }
+ else {
+ desc = _('no link');
+ }
+
+ dom.content(node, [
+ E('img', {
+ 'class': 'middle',
+ 'src': L.resource('icons/port_%s.png').format(carrier ? 'up' : 'down')
+ }),
+ '\x0a', desc
+ ]);
+
+ if (title)
+ node.setAttribute('data-tooltip', title);
+ else
+ node.removeAttribute('data-tooltip');
+
+ return node;
+}
+
+function renderPortStatus(dev) {
+ return updatePortStatus(E('span', {
+ 'class': 'ifacebadge port-status-link',
+ 'data-device': dev.getName()
+ }), dev);
+}
+
+function updatePlaceholders(opt, section_id) {
+ var dev = network.instantiateDevice(opt.getUIElement(section_id).getValue());
+
+ for (var i = 0, co; (co = opt.section.children[i]) != null; i++) {
+ if (co !== opt) {
+ switch (co.option) {
+ case 'mtu':
+ case 'mtu6':
+ co.getUIElement(section_id).setPlaceholder(dev.getMTU());
+ break;
+
+ case 'macaddr':
+ co.getUIElement(section_id).setPlaceholder(dev.getMAC());
+ break;
+
+ case 'txqueuelen':
+ co.getUIElement(section_id).setPlaceholder(dev._devstate('qlen'));
+ break;
+ }
+ }
+ }
+}
+
+
+var cbiTagValue = form.Value.extend({
+ renderWidget: function(section_id, option_index, cfgvalue) {
+ var widget = new ui.Dropdown(cfgvalue || ['-'], {
+ '-': E([], [
+ E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '—' ]),
+ E('span', { 'class': 'hide-close' }, [ _('Do not participate', 'VLAN port state') ])
+ ]),
+ 'u': E([], [
+ E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ 'u' ]),
+ E('span', { 'class': 'hide-close' }, [ _('Egress untagged', 'VLAN port state') ])
+ ]),
+ 't': E([], [
+ E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ 't' ]),
+ E('span', { 'class': 'hide-close' }, [ _('Egress tagged', 'VLAN port state') ])
+ ]),
+ '*': E([], [
+ E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '*' ]),
+ E('span', { 'class': 'hide-close' }, [ _('Primary VLAN ID', 'VLAN port state') ])
+ ])
+ }, {
+ id: this.cbid(section_id),
+ sort: [ '-', 'u', 't', '*' ],
+ optional: false,
+ multiple: true
+ });
+
+ var field = this;
+
+ widget.toggleItem = function(sb, li, force_state) {
+ var lis = li.parentNode.querySelectorAll('li'),
+ toggle = ui.Dropdown.prototype.toggleItem;
+
+ toggle.apply(this, [sb, li, force_state]);
+
+ if (force_state != null)
+ return;
+
+ switch (li.getAttribute('data-value'))
+ {
+ case '-':
+ if (li.hasAttribute('selected')) {
+ for (var i = 0; i < lis.length; i++) {
+ switch (lis[i].getAttribute('data-value')) {
+ case '-':
+ break;
+
+ case '*':
+ toggle.apply(this, [sb, lis[i], false]);
+ lis[i].setAttribute('unselectable', '');
+ break;
+
+ default:
+ toggle.apply(this, [sb, lis[i], false]);
+ }
+ }
+ }
+ break;
+
+ case 't':
+ case 'u':
+ if (li.hasAttribute('selected')) {
+ for (var i = 0; i < lis.length; i++) {
+ switch (lis[i].getAttribute('data-value')) {
+ case li.getAttribute('data-value'):
+ break;
+
+ case '*':
+ lis[i].removeAttribute('unselectable');
+ break;
+
+ default:
+ toggle.apply(this, [sb, lis[i], false]);
+ }
+ }
+ }
+ else {
+ toggle.apply(this, [sb, li, true]);
+ }
+ break;
+
+ case '*':
+ if (li.hasAttribute('selected')) {
+ var section_ids = field.section.cfgsections();
+
+ for (var i = 0; i < section_ids.length; i++) {
+ var other_widget = field.getUIElement(section_ids[i]),
+ other_value = L.toArray(other_widget.getValue());
+
+ if (other_widget === this)
+ continue;
+
+ var new_value = other_value.filter(function(v) { return v != '*' });
+
+ if (new_value.length == other_value.length)
+ continue;
+
+ other_widget.setValue(new_value);
+ break;
+ }
+ }
+ }
+ };
+
+ var node = widget.render();
+
+ node.style.minWidth = '4em';
+
+ if (cfgvalue == '-')
+ node.querySelector('li[data-value="*"]').setAttribute('unselectable', '');
+
+ return E('div', { 'style': 'display:inline-block' }, node);
+ },
+
+ cfgvalue: function(section_id) {
+ var ports = L.toArray(uci.get('network', section_id, 'ports'));
+
+ for (var i = 0; i < ports.length; i++) {
+ var s = ports[i].split(/:/);
+
+ if (s[0] != this.port)
+ continue;
+
+ var t = /t/.test(s[1] || '') ? 't' : 'u';
+
+ return /\*/.test(s[1] || '') ? [t, '*'] : [t];
+ }
+
+ return ['-'];
+ },
+
+ write: function(section_id, value) {
+ var ports = [];
+
+ for (var i = 0; i < this.section.children.length; i++) {
+ var opt = this.section.children[i];
+
+ if (opt.port) {
+ var val = L.toArray(opt.formvalue(section_id)).join('');
+
+ switch (val) {
+ case '-':
+ break;
+
+ case 'u':
+ ports.push(opt.port);
+ break;
+
+ default:
+ ports.push('%s:%s'.format(opt.port, val));
+ break;
+ }
+ }
+ }
+
+ uci.set('network', section_id, 'ports', ports);
+ },
+
+ remove: function() {}
+});
+
+return baseclass.extend({
+ replaceOption: function(s, tabName, optionClass, optionName, optionTitle, optionDescription) {
+ var o = s.getOption(optionName);
+
+ if (o) {
+ if (o.tab) {
+ s.tabs[o.tab].children = s.tabs[o.tab].children.filter(function(opt) {
+ return opt.option != optionName;
+ });
+ }
+
+ s.children = s.children.filter(function(opt) {
+ return opt.option != optionName;
+ });
+ }
+
+ return s.taboption(tabName, optionClass, optionName, optionTitle, optionDescription);
+ },
+
+ addDeviceOptions: function(s, dev, isNew) {
+ var parent_dev = dev ? dev.getParent() : null,
+ o, ss;
+
+ 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.replaceOption(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.validate = function(section_id, value) {
+ if (value == 'bridge' || value == 'veth')
+ updatePlaceholders(this.section.getOption('name_complex'), section_id);
+
+ return true;
+ };
+
+ o = this.replaceOption(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.filter = function(section_id, value) {
+ var dev = network.instantiateDevice(value);
+ return !deviceSectionExists(section_id, value) && (dev.getType() != 'wifi' || dev.isUp());
+ };
+ o.validate = function(section_id, value) {
+ updatePlaceholders(this, section_id);
+
+ return deviceSectionExists(section_id, value)
+ ? _('A configuration for the device "%s" already exists').format(value) : true;
+ };
+ o.onchange = function(ev, section_id, values) {
+ updatePlaceholders(this, section_id);
+ };
+ o.depends('type', '');
+
+ o = this.replaceOption(s, 'devgeneral', widgets.DeviceSelect, 'ifname_single', _('Base device'));
+ o.readonly = !isNew;
+ o.rmempty = false;
+ o.noaliases = true;
+ o.default = (dev ? dev.getName() : '').match(/^.+\.\d+$/) ? dev.getName().replace(/\.\d+$/, '') : '';
+ o.ucioption = 'ifname';
+ o.filter = function(section_id, value) {
+ var dev = network.instantiateDevice(value);
+ return (dev.getType() != 'wifi' || dev.isUp());
+ };
+ o.validate = function(section_id, value) {
+ updatePlaceholders(this, section_id);
+
+ 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;
+
+ while (deviceSectionExists(section_id, '%smac%d'.format(value, i)))
+ i++;
+
+ name.setValue('%smac%d'.format(value, i));
+ name.triggerValidation();
+ }
+ }
+
+ return true;
+ };
+ o.onchange = function(ev, section_id, values) {
+ updatePlaceholders(this, section_id);
+ };
+ o.depends('type', '8021q');
+ o.depends('type', '8021ad');
+ o.depends('type', 'macvlan');
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'vid', _('VLAN ID'));
+ o.readonly = !isNew;
+ o.datatype = 'range(1, 4094)';
+ o.rmempty = false;
+ o.default = (dev ? dev.getName() : '').match(/^.+\.\d+$/) ? dev.getName().replace(/^.+\./, '') : '';
+ o.validate = function(section_id, value) {
+ var base = this.section.formvalue(section_id, 'ifname_single'),
+ vid = this.section.formvalue(section_id, 'vid'),
+ name = this.section.getUIElement(section_id, 'name_complex');
+
+ if (base && vid && name && !name.isChanged()) {
+ name.setValue('%s.%d'.format(base, vid));
+ name.triggerValidation();
+ }
+
+ return true;
+ };
+ o.depends('type', '8021q');
+ o.depends('type', '8021ad');
+
+ o = this.replaceOption(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');
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'name_complex', _('Device name'));
+ o.rmempty = false;
+ o.datatype = 'maxlength(15)';
+ o.readonly = !isNew;
+ o.ucioption = 'name';
+ o.validate = function(section_id, value) {
+ var dev = network.instantiateDevice(value);
+
+ if (deviceSectionExists(section_id, value) || (isNew && (dev.dev || {}).idx))
+ return _('The device name "%s" is already taken').format(value);
+
+ return true;
+ };
+ o.depends({ type: '', '!reverse': true });
+
+ o = this.replaceOption(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.replaceOption(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.replaceOption(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 = 'ports';
+ 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.')
+ o.onchange = function(ev, section_id, values) {
+ ss.updatePorts(values);
+
+ return ss.parse().then(function() {
+ ss.redraw();
+ });
+ };
+ o.depends('type', 'bridge');
+
+ 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, 'devadvanced', form.Value, 'priority', _('Priority'));
+ o.placeholder = '32767';
+ o.datatype = 'range(0, 65535)';
+ o.depends('type', 'bridge');
+
+ 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, 'devadvanced', form.Flag, 'stp', _('Enable STP '), _('Enables the Spanning Tree Protocol on this bridge'));
+ o.default = o.disabled;
+ o.depends('type', 'bridge');
+
+ 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, '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, '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, 'devadvanced', form.Flag, 'igmp_snooping', _('Enable IGMP snooping'), _('Enables IGMP snooping on this bridge'));
+ o.default = o.disabled;
+ o.depends('type', 'bridge');
+
+ 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, '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, '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, '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, '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) {
+ var qiopt = L.toArray(this.map.lookupOption('query_interval', section_id))[0],
+ qival = qiopt ? (qiopt.formvalue(section_id) || qiopt.placeholder) : '';
+
+ if (value != '' && qival != '' && +value >= +qival)
+ return _('The query response interval must be lower than the query interval value');
+
+ return true;
+ };
+ o.depends({ type: 'bridge', multicast_querier: '1' });
+
+ 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.replaceOption(s, 'devgeneral', form.Value, 'mtu', _('MTU'));
+ o.datatype = 'range(576, 9200)';
+ o.validate = function(section_id, value) {
+ var parent_mtu = (dev && dev.getType() == 'vlan') ? (parent_dev ? parent_dev.getMTU() : null) : null;
+
+ if (parent_mtu !== null && +value > parent_mtu)
+ return _('The MTU must not exceed the parent device MTU of %d bytes').format(parent_mtu);
+
+ return true;
+ };
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'macaddr', _('MAC address'));
+ o.datatype = 'macaddr';
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'peer_name', _('Peer device name'));
+ o.rmempty = true;
+ o.datatype = 'maxlength(15)';
+ o.depends('type', 'veth');
+ o.load = function(section_id) {
+ var sections = uci.sections('network', 'device'),
+ idx = 0;
+
+ for (var i = 0; i < sections.length; i++)
+ if (sections[i]['.name'] == section_id)
+ break;
+ else if (sections[i].type == 'veth')
+ idx++;
+
+ this.placeholder = 'veth%d'.format(idx);
+
+ return form.Value.prototype.load.apply(this, arguments);
+ };
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'peer_macaddr', _('Peer MAC address'));
+ o.rmempty = true;
+ o.datatype = 'macaddr';
+ o.depends('type', 'veth');
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'txqueuelen', _('TX queue length'));
+ o.placeholder = dev ? dev._devstate('qlen') : '';
+ o.datatype = 'uinteger';
+
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'promisc', _('Enable promiscuous mode'));
+ o.default = o.disabled;
+
+ o = this.replaceOption(s, 'devadvanced', form.ListValue, 'rpfilter', _('Reverse path filter'));
+ o.default = '';
+ o.value('', _('disabled'));
+ o.value('loose', _('Loose filtering'));
+ o.value('strict', _('Strict filtering'));
+ o.cfgvalue = function(section_id) {
+ var val = form.ListValue.prototype.cfgvalue.apply(this, [section_id]);
+
+ switch (val || '') {
+ case 'loose':
+ case '1':
+ return 'loose';
+
+ case 'strict':
+ case '2':
+ return 'strict';
+
+ default:
+ return '';
+ }
+ };
+
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'acceptlocal', _('Accept local'), _('Accept packets with local source addresses'));
+ o.default = o.disabled;
+
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'sendredirects', _('Send ICMP redirects'));
+ o.default = o.enabled;
+
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'neighreachabletime', _('Neighbour cache validity'), _('Time in milliseconds'));
+ o.placeholder = '30000';
+ o.datatype = 'uinteger';
+
+ o = this.replaceOption(s, 'devadvanced', form.Value, 'neighgcstaletime', _('Stale neighbour cache timeout'), _('Timeout in seconds'));
+ o.placeholder = '60';
+ o.datatype = 'uinteger';
+
+ o = this.replaceOption(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 = this.replaceOption(s, 'devgeneral', form.Flag, 'ipv6', _('Enable IPv6'));
+ o.migrate = false;
+ o.default = o.enabled;
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'mtu6', _('IPv6 MTU'));
+ o.datatype = 'max(9200)';
+ o.depends('ipv6', '1');
+
+ o = this.replaceOption(s, 'devgeneral', form.Value, 'dadtransmits', _('DAD transmits'), _('Amount of Duplicate Address Detection probes to send'));
+ o.placeholder = '1';
+ o.datatype = 'uinteger';
+ o.depends('ipv6', '1');
+
+
+ o = this.replaceOption(s, 'devadvanced', form.Flag, 'multicast', _('Enable multicast support'));
+ o.default = o.enabled;
+
+ o = this.replaceOption(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('multicast', '1');
+
+ o = this.replaceOption(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('multicast', '1');
+
+ if (isBridgePort(dev)) {
+ o = this.replaceOption(s, 'brport', form.Flag, 'learning', _('Enable MAC address learning'));
+ o.default = o.enabled;
+
+ o = this.replaceOption(s, 'brport', form.Flag, 'unicast_flood', _('Enable unicast flooding'));
+ o.default = o.enabled;
+
+ o = this.replaceOption(s, 'brport', form.Flag, 'isolated', _('Port isolation'), _('Only allow communication with non-isolated bridge ports when enabled'));
+ o.default = o.disabled;
+
+ o = this.replaceOption(s, 'brport', form.ListValue, 'multicast_router', _('Multicast routing'));
+ o.value('', _('Never'));
+ o.value('1', _('Learn'));
+ o.value('2', _('Always'));
+ o.depends('multicast', '1');
+
+ o = this.replaceOption(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('multicast', '1');
+
+ o = this.replaceOption(s, 'brport', form.Flag, 'multicast_fast_leave', _('Enable multicast fast leave'));
+ o.default = o.disabled;
+ o.depends('multicast', '1');
+ }
+
+ o = this.replaceOption(s, 'bridgevlan', form.Flag, 'vlan_filtering', _('Enable VLAN filtering'));
+ o.depends('type', 'bridge');
+ o.updateDefaultValue = function(section_id) {
+ var device = uci.get('network', s.section, 'name'),
+ uielem = this.getUIElement(section_id),
+ has_vlans = false;
+
+ uci.sections('network', 'bridge-vlan', function(bvs) {
+ has_vlans = has_vlans || (bvs.device == device);
+ });
+
+ this.default = has_vlans ? this.enabled : this.disabled;
+
+ if (uielem && !uielem.isChanged())
+ uielem.setValue(this.default);
+ };
+
+ o = this.replaceOption(s, 'bridgevlan', form.SectionValue, 'bridge-vlan', form.TableSection, 'bridge-vlan');
+ o.depends('type', 'bridge');
+
+ ss = o.subsection;
+ ss.addremove = true;
+ ss.anonymous = true;
+
+ ss.renderHeaderRows = function(/* ... */) {
+ var node = form.TableSection.prototype.renderHeaderRows.apply(this, arguments);
+
+ node.querySelectorAll('.th').forEach(function(th) {
+ th.classList.add('left');
+ th.classList.add('middle');
+ });
+
+ return node;
+ };
+
+ ss.filter = function(section_id) {
+ var devname = uci.get('network', s.section, 'name');
+ return (uci.get('network', section_id, 'device') == devname);
+ };
+
+ ss.render = function(/* ... */) {
+ return form.TableSection.prototype.render.apply(this, arguments).then(L.bind(function(node) {
+ node.style.overflow = 'auto hidden';
+ node.style.paddingTop = '1em';
+
+ if (this.node)
+ this.node.parentNode.replaceChild(node, this.node);
+
+ this.node = node;
+
+ return node;
+ }, this));
+ };
+
+ ss.redraw = function() {
+ return this.load().then(L.bind(this.render, this));
+ };
+
+ ss.updatePorts = function(ports) {
+ var devices = ports.map(function(port) {
+ return network.instantiateDevice(port)
+ }).filter(function(dev) {
+ return dev.getType() != 'wifi' || dev.isUp();
+ });
+
+ this.children = this.children.filter(function(opt) { return !opt.option.match(/^port_/) });
+
+ for (var i = 0; i < devices.length; i++) {
+ o = ss.option(cbiTagValue, 'port_%s'.format(sfh(devices[i].getName())), renderDevBadge(devices[i]), renderPortStatus(devices[i]));
+ o.port = devices[i].getName();
+ }
+
+ var section_ids = this.cfgsections(),
+ device_names = devices.reduce(function(names, dev) { names[dev.getName()] = true; return names }, {});
+
+ for (var i = 0; i < section_ids.length; i++) {
+ var old_spec = L.toArray(uci.get('network', section_ids[i], 'ports')),
+ new_spec = old_spec.filter(function(spec) { return device_names[spec.replace(/:[ut*]+$/, '')] });
+
+ if (old_spec.length != new_spec.length)
+ uci.set('network', section_ids[i], 'ports', new_spec.length ? new_spec : null);
+ }
+ };
+
+ ss.handleAdd = function(ev) {
+ return s.parse().then(L.bind(function() {
+ var device = uci.get('network', s.section, 'name'),
+ section_ids = this.cfgsections(),
+ section_id = null,
+ max_vlan_id = 0;
+
+ if (!device)
+ return;
+
+ for (var i = 0; i < section_ids.length; i++) {
+ var vid = +uci.get('network', section_ids[i], 'vlan');
+
+ if (vid > max_vlan_id)
+ max_vlan_id = vid;
+ }
+
+ section_id = uci.add('network', 'bridge-vlan');
+ uci.set('network', section_id, 'device', device);
+ uci.set('network', section_id, 'vlan', max_vlan_id + 1);
+
+ s.children.forEach(function(opt) {
+ switch (opt.option) {
+ case 'type':
+ case 'name_complex':
+ var input = opt.map.findElement('id', 'widget.%s'.format(opt.cbid(s.section)));
+ if (input)
+ input.disabled = true;
+ break;
+ }
+ });
+
+ s.getOption('vlan_filtering').updateDefaultValue(s.section);
+
+ s.map.addedVLANs = s.map.addedVLANs || [];
+ s.map.addedVLANs.push(section_id);
+
+ return this.redraw();
+ }, this));
+ };
+
+ o = ss.option(form.Value, 'vlan', _('VLAN ID'));
+ o.datatype = 'range(1, 4094)';
+
+ o.renderWidget = function(/* ... */) {
+ var node = form.Value.prototype.renderWidget.apply(this, arguments);
+
+ node.style.width = '5em';
+
+ return node;
+ };
+
+ o.validate = function(section_id, value) {
+ var section_ids = this.section.cfgsections();
+
+ for (var i = 0; i < section_ids.length; i++) {
+ if (section_ids[i] == section_id)
+ continue;
+
+ if (uci.get('network', section_ids[i], 'vlan') == value)
+ return _('The VLAN ID must be unique');
+ }
+
+ return true;
+ };
+
+ o = ss.option(form.Flag, 'local', _('Local'));
+ o.default = o.enabled;
+
+ var ports = [];
+
+ var seen_ports = {};
+
+ L.toArray(uci.get('network', s.section, 'ports')).forEach(function(port) {
+ seen_ports[port] = true;
+ });
+
+ uci.sections('network', 'bridge-vlan', function(bvs) {
+ if (uci.get('network', s.section, 'name') != bvs.device)
+ return;
+
+ L.toArray(bvs.ports).forEach(function(portspec) {
+ var m = portspec.match(/^([^:]+)(?::[ut*]+)?$/);
+
+ if (m)
+ seen_ports[m[1]] = true;
+ });
+ });
+
+ for (var port_name in seen_ports)
+ ports.push(port_name);
+
+ ports.sort(function(a, b) {
+ var m1 = a.match(/^(.+?)([0-9]*)$/),
+ m2 = b.match(/^(.+?)([0-9]*)$/);
+
+ if (m1[1] < m2[1])
+ return -1;
+ else if (m1[1] > m2[1])
+ return 1;
+ else
+ return +(m1[2] || 0) - +(m2[2] || 0);
+ });
+
+ ss.updatePorts(ports);
+ },
+
+ updateDevBadge: updateDevBadge,
+ updatePortStatus: updatePortStatus
+});
diff --git a/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js b/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
index ed2b50866..4dd90cc32 100644
--- a/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
+++ b/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
@@ -34,8 +34,8 @@ CBILeaseStatus = form.DummyValue.extend({
E('table', { 'id': 'lease_status_table', 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, _('Hostname')),
- E('th', { 'class': 'th' }, _('IPv4-Address')),
- E('th', { 'class': 'th' }, _('MAC-Address')),
+ E('th', { 'class': 'th' }, _('IPv4 address')),
+ E('th', { 'class': 'th' }, _('MAC address')),
E('th', { 'class': 'th' }, _('Lease time remaining'))
]),
E('tr', { 'class': 'tr placeholder' }, [
@@ -53,7 +53,7 @@ CBILease6Status = form.DummyValue.extend({
E('table', { 'id': 'lease6_status_table', 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, _('Host')),
- E('th', { 'class': 'th' }, _('IPv6-Address')),
+ E('th', { 'class': 'th' }, _('IPv6 address')),
E('th', { 'class': 'th' }, _('DUID')),
E('th', { 'class': 'th' }, _('Lease time remaining'))
]),
@@ -279,7 +279,8 @@ return view.extend({
o.optional = true;
o.placeholder = '/example.org/10.1.2.3';
- // o.validate = validateServerSpec;
+ o.validate = validateServerSpec;
+
o = s.taboption('general', form.DynamicList, 'address', _('Addresses'),
_('List of domains to force to an IP address.'));
@@ -287,6 +288,7 @@ return view.extend({
o.optional = true;
o.placeholder = '/router.local/192.168.0.1';
+
o = s.taboption('general', form.Flag, 'rebind_protection',
_('Rebind protection'),
_('Discard upstream RFC1918 responses'));
@@ -407,7 +409,7 @@ return view.extend({
o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null,
_('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + ' ' +
- _('Use the Add Button to add a new lease entry. The MAC-Address identifies the host, the IPv4-Address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.'));
+ _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.'));
ss = o.subsection;
@@ -448,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);
@@ -457,16 +463,35 @@ 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);
});
+ so.write = function(section, value) {
+ var ip = this.map.lookupOption('ip', section)[0].formvalue(section);
+ var hosts = uci.sections('dhcp', 'host');
+ var section_removed = false;
+
+ for (var i = 0; i < hosts.length; i++) {
+ if (ip == hosts[i].ip) {
+ uci.set('dhcp', hosts[i]['.name'], 'mac', [hosts[i].mac, value].join(' '));
+ uci.remove('dhcp', section);
+ section_removed = true;
+ break;
+ }
+ }
+
+ if (!section_removed) {
+ uci.set('dhcp', section, 'mac', value);
+ }
+ }
+
so = ss.option(form.Value, 'ip', _('IPv4 -Address'));
so.datatype = 'or(ip4addr,"ignore")';
so.validate = function(section, value) {
@@ -480,19 +505,21 @@ 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;
});
- so = ss.option(form.Value, 'gw', _('Gateway'));
- so.datatype = 'or(ip4addr,"ignore")';
- so.rmempty = true;
+ 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'), _('The lease time is in minutes (mini 2m), hours (eg 1h) or "infinite"'));
- so.placeholder = '12h';
+ so = ss.option(form.Value, 'leasetime', _('Lease time'));
so.rmempty = true;
so = ss.option(form.Value, 'duid', _('DUID '));
@@ -547,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/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js b/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
index cd0dacbf6..93ebf5ba6 100644
--- a/luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
+++ b/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/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js b/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
index 9944c0920..ff179d404 100644
--- a/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
+++ b/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
@@ -9,6 +9,7 @@
'require network';
'require firewall';
'require tools.widgets as widgets';
+'require tools.network as nettools';
var isReadonlyView = !L.hasViewPermission() || null;
@@ -76,7 +77,6 @@ function render_status(node, ifc, with_device) {
macaddr = maindev ? maindev.getMAC() : null;
return L.itemlist(node, [
- _('Label'), ifc.get('label'),
_('Protocol'), with_device ? null : (desc || '?'),
_('Device'), with_device ? (maindev ? maindev.getShortName() : E('em', _('Not present'))) : null,
_('Uptime'), (!changecount && ifc.isUp()) ? '%t'.format(ifc.getUptime()) : null,
@@ -128,7 +128,7 @@ function render_modal_status(node, ifc) {
function render_ifacebox_status(node, ifc) {
var dev = ifc.getL3Device() || ifc.getDevice(),
- subdevs = ifc.getDevices(),
+ subdevs = dev ? dev.getPorts() : null,
c = [ render_iface(dev, ifc.isAlias()) ];
if (subdevs && subdevs.length) {
@@ -228,6 +228,39 @@ function get_netmask(s, use_cfgvalue) {
return subnetmask;
}
+var cbiRichListValue = form.ListValue.extend({
+ renderWidget: function(section_id, option_index, cfgvalue) {
+ var choices = this.transformChoices();
+ var widget = new ui.Dropdown((cfgvalue != null) ? cfgvalue : this.default, choices, {
+ id: this.cbid(section_id),
+ sort: this.keylist,
+ optional: true,
+ select_placeholder: this.select_placeholder || this.placeholder,
+ custom_placeholder: this.custom_placeholder || this.placeholder,
+ validate: L.bind(this.validate, this, section_id),
+ disabled: (this.readonly != null) ? this.readonly : this.map.readonly
+ });
+
+ return widget.render();
+ },
+
+ value: function(value, title, description) {
+ if (description) {
+ form.ListValue.prototype.value.call(this, value, E([], [
+ E('span', { 'class': 'hide-open' }, [ title ]),
+ E('div', { 'class': 'hide-close', 'style': 'min-width:25vw' }, [
+ E('strong', [ title ]),
+ E('br'),
+ E('span', { 'style': 'white-space:normal' }, description)
+ ])
+ ]));
+ }
+ else {
+ form.ListValue.prototype.value.call(this, value, title);
+ }
+ }
+});
+
return view.extend({
poll_status: function(map, networks) {
var resolveZone = null;
@@ -286,20 +319,142 @@ return view.extend({
btn2.disabled = isReadonlyView || btn1.classList.contains('spinning') || btn2.classList.contains('spinning') || dynamic || disabled;
}
+ document.querySelectorAll('.port-status-device[data-device]').forEach(function(node) {
+ nettools.updateDevBadge(node, network.instantiateDevice(node.getAttribute('data-device')));
+ });
+
+ document.querySelectorAll('.port-status-link[data-device]').forEach(function(node) {
+ nettools.updatePortStatus(node, network.instantiateDevice(node.getAttribute('data-device')));
+ });
+
return Promise.all([ resolveZone, network.flushCache() ]);
},
load: function() {
return Promise.all([
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),
+ 'mtu': ns.mtu,
+ 'macaddr': ns.macaddr,
+ 'igmp_snooping': ns.igmp_snooping
+ }));
+
+ tasks.push(uci.callSet('network', ns['.name'], {
+ 'type': '',
+ 'ifname': '',
+ 'mtu': '',
+ 'macaddr': '',
+ 'igmp_snooping': '',
+ '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.callSet('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;
+ var rtTables = data[2].map(function(l) {
+ var m = l.trim().match(/^(\d+)\s+(\S+)$/);
+ return m ? [ +m[1], m[2] ] : null;
+ }).filter(function(e) {
+ return e && e[0] > 0;
+ });
+
m = new form.Map('network');
m.tabbed = true;
m.chain('dhcp');
@@ -322,6 +477,8 @@ return view.extend({
s.tab('general', _('General Settings'));
s.tab('advanced', _('Advanced Settings'));
s.tab('physical', _('Physical Settings'));
+ s.tab('brport', _('Bridge port specific options'));
+ s.tab('bridgevlan', _('Bridge VLAN filtering'));
s.tab('firewall', _('Firewall Settings'));
s.tab('dhcp', _('DHCP Server'));
@@ -369,7 +526,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, ifname_master, proto_select, proto_switch, type, stp, igmp, ss, so;
+ o, proto_select, proto_switch, type, stp, igmp, ss, so;
if (!protoval)
return;
@@ -393,9 +550,6 @@ return view.extend({
}, this);
o.write = function() {};
- o = s.taboption('general', form.Value, 'label', _('Label'));
- o.modalonly = true;
- o.optional = true;
proto_select = s.taboption('general', form.ListValue, 'proto', _('Protocol'));
proto_select.modalonly = true;
@@ -412,170 +566,16 @@ 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;
- type = s.taboption('physical', form.ListValue, 'type', _('Type'));
- type.value('',_('Normal'));
- type.value('bridge',_('Bridge'));
- type.value('macvlan',_('MacVLAN'));
- type.write = type.remove = function(section_id, value) {
- var protocol = network.getProtocol(proto_select.formvalue(section_id)),
- ifnameopt = this.section.children.filter(function(o) {
- if (value == 'bridge')
- return o.option == 'ifname_multi';
- else if (value == 'macvlan')
- return o.option == 'ifname_master';
- else
- return o.option == 'ifname_single';
- })[0];
-
- 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());
-
- var new_ifnames = L.toArray(ifnameopt.formvalue(section_id));
-
- if (!value)
- new_ifnames.length = Math.max(new_ifnames.length, 1);
-
- old_ifnames.sort();
- new_ifnames.sort();
-
- 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', value);
- else
- uci.unset('network', section_id, 'type');
- };
-
- o = s.taboption('advanced', form.Value, 'ip6assign', _('IPv6 assignment length'), _('Assign a part of given length of every public IPv6-prefix to this interface'));
- o.value('', _('disabled'));
- o.value('64');
- o.datatype = 'max(64)';
-
- o = s.taboption('advanced', form.Value, 'ip6hint', _('IPv6 assignment hint'), _('Assign prefix parts using this hexadecimal subprefix ID for this interface.'));
- o.placeholder = '0';
- o.validate = function(section_id, value) {
- if (value == null || value == '')
- return true;
- var n = parseInt(value, 16);
- if (!/^(0x)?[0-9a-fA-F]+$/.test(value) || isNaN(n) || n >= 0xffffffff)
- return _('Expecting a hexadecimal assignment hint');
- return true;
- };
-
- for (var i = 33; i <= 64; i++)
- o.depends('ip6assign', String(i));
-
- o = s.taboption('advanced', form.DynamicList, 'ip6addr', _('IPv6 address'));
- o.datatype = 'ip6addr';
- o.placeholder = _('Add IPv6 address…');
- o.depends('ip6assign', '');
-
- o = s.taboption('advanced', form.Value, 'ip6gw', _('IPv6 gateway'));
- o.datatype = 'ip6addr("nomask")';
- o.depends('ip6assign', '');
-
- o = s.taboption('advanced', form.Value, 'ip6prefix', _('IPv6 routed prefix'), _('Public prefix routed to this device for distribution to clients.'));
- o.datatype = 'ip6addr';
- o.depends('ip6assign', '');
-
- o = s.taboption('advanced', form.Value, 'ip6ifaceid', _('IPv6 suffix'), _("Optional. Allowed values: 'eui64', 'random', fixed value like '::1' or '::1:2'. When IPv6 prefix (like 'a:b:c:d::') is received from a delegating server, use the suffix (like '::1') to form the IPv6 address ('a:b:c:d::1') for the interface."));
- o.datatype = 'ip6hostid';
- o.placeholder = '::1';
-
- stp = s.taboption('physical', form.Flag, 'stp', _('Enable STP '), _('Enables the Spanning Tree Protocol on this bridge'));
-
- igmp = s.taboption('physical', form.Flag, 'igmp_snooping', _('Enable IGMP snooping'), _('Enables IGMP snooping on this bridge'));
-
- ifname_master = s.taboption('physical', widgets.DeviceSelect, 'ifname_master', _('Base interface'));
- ifname_master.nobridges = true;
- ifname_master.noaliases = true;
- ifname_master.optional = false;
- ifname_master.modalonly = true;
- ifname_master.network = ifc.getName();
- //ifname_master.write = ifname_master.remove = function() {};
- ifname_master.ucioption = 'masterintf';
- //ifname_master.cfgvalue = function(section_id) {
- // return uci.get('network', section_id, 'masterintf');
- //};
- //ifname_master.write = function(section_id, value) {
- // uci.set('network', section_id, 'masterintf', value);
- //};
-
- ifname_single = s.taboption('physical', widgets.DeviceSelect, 'ifname_single', _('Interface'));
- ifname_single.nobridges = ifc.isBridge();
- ifname_single.noaliases = false;
- ifname_single.optional = false;
- ifname_single.network = ifc.getName();
- ifname_single.write = ifname_single.remove = function() {};
-
- ifname_multi = s.taboption('physical', widgets.DeviceSelect, 'ifname_multi', _('Interface'));
- ifname_multi.nobridges = ifc.isBridge();
- ifname_multi.noaliases = true;
- ifname_multi.multiple = true;
- ifname_multi.optional = true;
- ifname_multi.network = ifc.getName();
- ifname_multi.display_size = 6;
- ifname_multi.write = ifname_multi.remove = function(section_id, value) {
- var old_ifnames = [],
- devs = ifc.getDevices() || L.toArray(ifc.getDevice());
-
- for (var i = 0; i < devs.length; i++)
- old_ifnames.push(devs[i].getName());
-
- var new_ifnames = L.toArray(value);
-
- if (value == null)
- return;
-
- old_ifnames.sort();
- new_ifnames.sort();
-
- 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;
- }
- }
- };
-
-
- ifname_single.cfgvalue = ifname_multi.cfgvalue = function(section_id) {
- var devs = ifc.getDevices() || L.toArray(ifc.getDevice()),
- ifnames = [];
-
- for (var i = 0; i < devs.length; i++)
- ifnames.push(devs[i].getName());
-
- return ifnames;
- };
-
if (L.hasSystemFeature('firewall')) {
o = s.taboption('firewall', widgets.ZoneSelect, '_zone', _('Create / Assign firewall-zone'), _('Choose the firewall zone you want to assign to this interface. Select unspecified to remove the interface from the associated zone or fill out the custom field to define a new zone and attach the interface to it.'));
o.network = ifc.getName();
@@ -619,31 +619,10 @@ return view.extend({
if (protocols[i].getProtocol() != uci.get('network', s.section, 'proto'))
proto_switch.depends('proto', protocols[i].getProtocol());
-
- if (!protocols[i].isVirtual()) {
- type.depends('proto', protocols[i].getProtocol());
- stp.depends({ type: 'bridge', proto: protocols[i].getProtocol() });
- igmp.depends({ type: 'bridge', proto: protocols[i].getProtocol() });
- ifname_single.depends({ type: '', proto: protocols[i].getProtocol() });
- ifname_master.depends({ type: 'macvlan', proto: protocols[i].getProtocol() });
- ifname_multi.depends({ type: 'bridge', proto: protocols[i].getProtocol() });
- }
}
- o = s.taboption('advanced', form.ListValue, 'multipath', _('Multipath setting'), _('Only one interface must be set as Master.'));
- o.value('on',_('Enabled'));
- o.value('off',_('Disabled'));
- o.value('master',_('Master'));
- o.value('backup',_('Backup'));
- o.default = 'off';
-
- o = s.taboption('advanced', form.Value, 'addlatency', _('Additional latency'));
- o.datatype = 'uinteger';
- o.default = '0';
-
if (L.hasSystemFeature('dnsmasq') || L.hasSystemFeature('odhcpd')) {
o = s.taboption('dhcp', form.SectionValue, '_dhcp', form.TypedSection, 'dhcp');
- o.depends('proto', 'static');
ss = o.subsection;
ss.uciconfig = 'dhcp';
@@ -653,6 +632,7 @@ return view.extend({
ss.tab('general', _('General Setup'));
ss.tab('advanced', _('Advanced Settings'));
ss.tab('ipv6', _('IPv6 Settings'));
+ ss.tab('ipv6-ra', _('IPv6 RA Settings'));
ss.filter = function(section_id) {
return (uci.get('dhcp', section_id, 'interface') == ifc.getName());
@@ -668,9 +648,15 @@ return view.extend({
this.map.save(function() {
uci.add('dhcp', 'dhcp', section_id);
uci.set('dhcp', section_id, 'interface', section_id);
- uci.set('dhcp', section_id, 'start', 100);
- uci.set('dhcp', section_id, 'limit', 150);
- uci.set('dhcp', section_id, 'leasetime', '12h');
+
+ if (protoval == 'static') {
+ uci.set('dhcp', section_id, 'start', 100);
+ uci.set('dhcp', section_id, 'limit', 150);
+ uci.set('dhcp', section_id, 'leasetime', '12h');
+ }
+ else {
+ uci.set('dhcp', section_id, 'ignore', 1);
+ }
});
}, ifc.getName())
}, _('Setup DHCP Server'))
@@ -679,108 +665,389 @@ return view.extend({
ss.taboption('general', form.Flag, 'ignore', _('Ignore interface'), _('Disable DHCP for this interface.'));
- so = ss.taboption('general', form.Value, 'start', _('Start'), _('Lowest leased address as offset from the network address.'));
- so.optional = true;
- so.datatype = 'or(uinteger,ip4addr("nomask"))';
- so.default = '100';
+ if (protoval == 'static') {
+ so = ss.taboption('general', form.Value, 'start', _('Start'), _('Lowest leased address as offset from the network address.'));
+ so.optional = true;
+ so.datatype = 'or(uinteger,ip4addr("nomask"))';
+ so.default = '100';
- so = ss.taboption('general', form.Value, 'limit', _('Limit'), _('Maximum number of leased addresses.'));
- so.optional = true;
- so.datatype = 'uinteger';
- so.default = '150';
+ so = ss.taboption('general', form.Value, 'limit', _('Limit'), _('Maximum number of leased addresses.'));
+ so.optional = true;
+ so.datatype = 'uinteger';
+ so.default = '150';
- so = ss.taboption('general', form.Value, 'leasetime', _('Lease time'), _('Expiry time of leased addresses, minimum is 2 minutes (2m
).'));
- so.optional = true;
- so.default = '12h';
+ so = ss.taboption('general', form.Value, 'leasetime', _('Lease time'), _('Expiry time of leased addresses, minimum is 2 minutes (2m
).'));
+ so.optional = true;
+ so.default = '12h';
- so = ss.taboption('advanced', form.Flag, 'dynamicdhcp', _('Dynamic DHCP '), _('Dynamically allocate DHCP addresses for clients. If disabled, only clients having static leases will be served.'));
- so.default = so.enabled;
+ so = ss.taboption('advanced', form.Flag, 'dynamicdhcp', _('Dynamic DHCP '), _('Dynamically allocate DHCP addresses for clients. If disabled, only clients having static leases will be served.'));
+ so.default = so.enabled;
- ss.taboption('advanced', form.Flag, 'force', _('Force'), _('Force DHCP on this network even if another server is detected.'));
+ ss.taboption('advanced', form.Flag, 'force', _('Force'), _('Force DHCP on this network even if another server is detected.'));
- // XXX: is this actually useful?
- //ss.taboption('advanced', form.Value, 'name', _('Name'), _('Define a name for this network.'));
+ // XXX: is this actually useful?
+ //ss.taboption('advanced', form.Value, 'name', _('Name'), _('Define a name for this network.'));
- so = ss.taboption('advanced', form.Value, 'netmask', _('IPv4 -Netmask'), _('Override the netmask sent to clients. Normally it is calculated from the subnet that is served.'));
- so.optional = true;
- so.datatype = 'ip4addr';
+ so = ss.taboption('advanced', form.Value, 'netmask', _('IPv4 -Netmask'), _('Override the netmask sent to clients. Normally it is calculated from the subnet that is served.'));
+ so.optional = true;
+ so.datatype = 'ip4addr';
- so.render = function(option_index, section_id, in_table) {
- this.placeholder = get_netmask(s, true);
- return form.Value.prototype.render.apply(this, [ option_index, section_id, in_table ]);
- };
+ so.render = function(option_index, section_id, in_table) {
+ this.placeholder = get_netmask(s, true);
+ return form.Value.prototype.render.apply(this, [ option_index, section_id, in_table ]);
+ };
+
+ so.validate = function(section_id, value) {
+ var uielem = this.getUIElement(section_id);
+ if (uielem)
+ uielem.setPlaceholder(get_netmask(s, false));
+ return form.Value.prototype.validate.apply(this, [ section_id, value ]);
+ };
+
+ ss.taboption('advanced', form.DynamicList, 'dhcp_option', _('DHCP-Options'), _('Define additional DHCP options, for example "6,192.168.2.1,192.168.2.2
" which advertises different DNS servers to clients.'));
+ }
+
+
+ var has_other_master = uci.sections('dhcp', 'dhcp').filter(function(s) {
+ return (s.interface != ifc.getName() && s.master == '1');
+ })[0];
+
+ so = ss.taboption('ipv6', form.Flag , 'master', _('Designated master'));
+ so.readonly = has_other_master ? true : false;
+ so.description = has_other_master
+ ? _('Interface "%h" is already marked as designated master.').format(has_other_master.interface || has_other_master['.name'])
+ : _('Set this interface as master for RA and DHCPv6 relaying as well as NDP proxying.')
+ ;
so.validate = function(section_id, value) {
- var uielem = this.getUIElement(section_id);
- if (uielem)
- uielem.setPlaceholder(get_netmask(s, false));
- return form.Value.prototype.validate.apply(this, [ section_id, value ]);
+ var hybrid_downstream_desc = _('Operate in relay mode if a designated master interface is configured and active, otherwise fall back to server mode .'),
+ ndp_downstream_desc = _('Operate in relay mode if a designated master interface is configured and active, otherwise disable NDP proxying.'),
+ hybrid_master_desc = _('Operate in relay mode if an upstream IPv6 prefix is present, otherwise disable service.'),
+ checked = this.formvalue(section_id),
+ dhcpv6 = this.section.getOption('dhcpv6').getUIElement(section_id),
+ ndp = this.section.getOption('ndp').getUIElement(section_id),
+ ra = this.section.getOption('ra').getUIElement(section_id);
+
+ if (checked == '1' || protoval != 'static') {
+ dhcpv6.node.querySelector('li[data-value="server"]').setAttribute('unselectable', '');
+
+ if (dhcpv6.getValue() == 'server')
+ dhcpv6.setValue('hybrid');
+
+ ra.node.querySelector('li[data-value="server"]').setAttribute('unselectable', '');
+
+ if (ra.getValue() == 'server')
+ ra.setValue('hybrid');
+ }
+
+ if (checked == '1') {
+ dhcpv6.node.querySelector('li[data-value="hybrid"] > div > span').innerHTML = hybrid_master_desc;
+ ra.node.querySelector('li[data-value="hybrid"] > div > span').innerHTML = hybrid_master_desc;
+ ndp.node.querySelector('li[data-value="hybrid"] > div > span').innerHTML = hybrid_master_desc;
+ }
+ else {
+ if (protoval == 'static') {
+ dhcpv6.node.querySelector('li[data-value="server"]').removeAttribute('unselectable');
+ ra.node.querySelector('li[data-value="server"]').removeAttribute('unselectable');
+ }
+
+ dhcpv6.node.querySelector('li[data-value="hybrid"] > div > span').innerHTML = hybrid_downstream_desc;
+ ra.node.querySelector('li[data-value="hybrid"] > div > span').innerHTML = hybrid_downstream_desc;
+ ndp.node.querySelector('li[data-value="hybrid"] > div > span').innerHTML = ndp_downstream_desc ;
+ }
+
+ return true;
};
- ss.taboption('advanced', form.DynamicList, 'dhcp_option', _('DHCP-Options'), _('Define additional DHCP options, for example "6,192.168.2.1,192.168.2.2
" which advertises different DNS servers to clients.'));
- for (var i = 0; i < ss.children.length; i++)
- if (ss.children[i].option != 'ignore')
- ss.children[i].depends('ignore', '0');
+ so = ss.taboption('ipv6', cbiRichListValue, 'ra', _('RA -Service'),
+ _('Configures the operation mode of the RA service on this interface.'));
+ so.value('', _('disabled'),
+ _('Do not send any RA messages on this interface.'));
+ so.value('server', _('server mode'),
+ _('Send RA messages advertising this device as IPv6 router.'));
+ so.value('relay', _('relay mode'),
+ _('Forward RA messages received on the designated master interface to downstream interfaces.'));
+ so.value('hybrid', _('hybrid mode'), ' ');
- so = ss.taboption('ipv6', form.ListValue, 'ra', _('Router Advertisement-Service'));
- so.value('', _('disabled'));
- so.value('server', _('server mode'));
- so.value('relay', _('relay mode'));
- so.value('hybrid', _('hybrid mode'));
- so = ss.taboption('ipv6', form.ListValue, 'dhcpv6', _('DHCPv6-Service'));
- so.value('', _('disabled'));
- so.value('server', _('server mode'));
- so.value('relay', _('relay mode'));
- so.value('hybrid', _('hybrid mode'));
-
- so = ss.taboption('ipv6', form.ListValue, 'ndp', _('NDP-Proxy'));
- so.value('', _('disabled'));
- so.value('relay', _('relay mode'));
- so.value('hybrid', _('hybrid mode'));
-
- 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.ListValue, 'ra_management', _('DHCPv6-Mode'), _('Default is stateless + stateful'));
- so.value('0', _('stateless'));
- so.value('1', _('stateless + stateful'));
- so.value('2', _('stateful-only'));
- so.depends('dhcpv6', 'server');
- so.depends('dhcpv6', 'hybrid');
- so.default = '1';
-
- so = ss.taboption('ipv6', form.Flag, 'ra_default', _('Always announce default router'), _('Announce as default router even if no public prefix is available.'));
+ so = ss.taboption('ipv6-ra', cbiRichListValue, 'ra_default', _('Default router'),
+ _('Configures the default router advertisement in RA messages.'));
+ so.value('', _('automatic'),
+ _('Announce this device as default router if a local IPv6 default route is present.'));
+ so.value('1', _('on available prefix'),
+ _('Announce this device as default router if a public IPv6 prefix is available, regardless of local default route availability.'));
+ so.value('2', _('forced'),
+ _('Announce this device as default router regardless of whether a prefix or default route is present.'));
so.depends('ra', 'server');
- so.depends('ra', 'hybrid');
+ so.depends({ ra: 'hybrid', master: '0' });
- ss.taboption('ipv6', form.DynamicList, 'dns', _('Announced DNS servers'));
- ss.taboption('ipv6', form.DynamicList, 'domain', _('Announced DNS domains'));
+ so = ss.taboption('ipv6-ra', form.Flag, 'ra_slaac', _('Enable SLAAC '),
+ _('Set the autonomous address-configuration flag in the prefix information options of sent RA messages. When enabled, clients will perform stateless IPv6 address autoconfiguration.'));
+ so.default = so.enabled;
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+
+ so = ss.taboption('ipv6-ra', cbiRichListValue, 'ra_flags', _('RA Flags'),
+ _('Specifies the flags sent in RA messages, for example to instruct clients to request further information via stateful DHCPv6.'));
+ so.value('managed-config', _('managed config (M)'),
+ _('The Managed address configuration (M) flag indicates that IPv6 addresses are available via DHCPv6.'));
+ so.value('other-config', _('other config (O)'),
+ _('The Other configuration (O) flag indicates that other information, such as DNS servers, is available via DHCPv6.'));
+ so.value('home-agent', _('mobile home agent (H)'),
+ _('The Mobile IPv6 Home Agent (H) flag indicates that the device is also acting as Mobile IPv6 home agent on this link.'));
+ so.multiple = true;
+ so.select_placeholder = _('none');
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+ so.cfgvalue = function(section_id) {
+ var flags = L.toArray(uci.get('dhcp', section_id, 'ra_flags'));
+ return flags.length ? flags : [ 'other-config' ];
+ };
+ so.remove = function(section_id) {
+ uci.set('dhcp', section_id, 'ra_flags', [ 'none' ]);
+ };
+
+ so = ss.taboption('ipv6-ra', form.Value, 'ra_maxinterval', _('Max RA interval'), _('Maximum time allowed between sending unsolicited RA . Default is 600 seconds.'));
+ so.optional = true;
+ so.datatype = 'uinteger';
+ so.placeholder = '600';
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+
+ so = ss.taboption('ipv6-ra', form.Value, 'ra_mininterval', _('Min RA interval'), _('Minimum time allowed between sending unsolicited RA . Default is 200 seconds.'));
+ so.optional = true;
+ so.datatype = 'uinteger';
+ so.placeholder = '200';
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+
+ so = ss.taboption('ipv6-ra', form.Value, 'ra_lifetime', _('RA Lifetime'), _('Router Lifetime published in RA messages. Maximum is 9000 seconds.'));
+ so.optional = true;
+ so.datatype = 'range(0, 9000)';
+ so.placeholder = '1800';
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+
+ so = ss.taboption('ipv6-ra', form.Value, 'ra_mtu', _('RA MTU'), _('The MTU to be published in RA messages. Minimum is 1280 bytes.'));
+ so.optional = true;
+ so.datatype = 'range(1280, 65535)';
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+ so.load = function(section_id) {
+ var dev = ifc.getL3Device();
+
+ if (dev) {
+ var path = "/proc/sys/net/ipv6/conf/%s/mtu".format(dev.getName());
+
+ return L.resolveDefault(fs.read(path), dev.getMTU()).then(L.bind(function(data) {
+ this.placeholder = data;
+ }, this));
+ }
+ };
+
+ so = ss.taboption('ipv6-ra', form.Value, 'ra_hoplimit', _('RA Hop Limit'), _('The maximum hops to be published in RA messages. Maximum is 255 hops.'));
+ so.optional = true;
+ so.datatype = 'range(0, 255)';
+ so.depends('ra', 'server');
+ so.depends({ ra: 'hybrid', master: '0' });
+ so.load = function(section_id) {
+ var dev = ifc.getL3Device();
+
+ if (dev) {
+ var path = "/proc/sys/net/ipv6/conf/%s/hop_limit".format(dev.getName());
+
+ return L.resolveDefault(fs.read(path), 64).then(L.bind(function(data) {
+ this.placeholder = data;
+ }, this));
+ }
+ };
+
+
+ so = ss.taboption('ipv6', cbiRichListValue, 'dhcpv6', _('DHCPv6-Service'),
+ _('Configures the operation mode of the DHCPv6 service on this interface.'));
+ so.value('', _('disabled'),
+ _('Do not offer DHCPv6 service on this interface.'));
+ so.value('server', _('server mode'),
+ _('Provide a DHCPv6 server on this interface and reply to DHCPv6 solicitations and requests.'));
+ so.value('relay', _('relay mode'),
+ _('Forward DHCPv6 messages between the designated master interface and downstream interfaces.'));
+ so.value('hybrid', _('hybrid mode'), ' ');
+
+
+ so = ss.taboption('ipv6', form.DynamicList, 'dns', _('Announced IPv6 DNS servers'),
+ _('Specifies a fixed list of IPv6 DNS server addresses to announce via DHCPv6. If left unspecified, the device will announce itself as IPv6 DNS server unless the Local IPv6 DNS server option is disabled.'));
+ so.datatype = 'ip6addr("nomask")'; /* restrict to IPv6 only for now since dnsmasq (DHCPv4) does not honour this option */
+ so.depends('dhcpv6', 'server');
+ so.depends({ dhcpv6: 'hybrid', master: '0' });
+
+ so = ss.taboption('ipv6', form.Flag, 'dns_service', _('Local IPv6 DNS server'),
+ _('Announce this device as IPv6 DNS server.'));
+ so.default = so.enabled;
+ so.depends({ dhcpv6: 'server', dns: /^$/ });
+ so.depends({ dhcpv6: 'hybrid', dns: /^$/, master: '0' });
+
+ so = ss.taboption('ipv6', form.DynamicList, 'domain', _('Announced DNS domains'),
+ _('Specifies a fixed list of DNS search domains to announce via DHCPv6. If left unspecified, the local device DNS search domain will be announced.'));
+ so.datatype = 'hostname';
+ so.depends('dhcpv6', 'server');
+ so.depends({ dhcpv6: 'hybrid', master: '0' });
+
+
+ so = ss.taboption('ipv6', cbiRichListValue, 'ndp', _('NDP -Proxy'),
+ _('Configures the operation mode of the NDP proxy service on this interface.'));
+ so.value('', _('disabled'),
+ _('Do not proxy any NDP packets.'));
+ so.value('relay', _('relay mode'),
+ _('Forward NDP NS and NA messages between the designated master interface and downstream interfaces.'));
+ so.value('hybrid', _('hybrid mode'), ' ');
+
+
+ so = ss.taboption('ipv6', form.Flag, 'ndproxy_routing', _('Learn routes'), _('Setup routes for proxied IPv6 neighbours.'));
+ so.default = so.enabled;
+ so.depends('ndp', 'relay');
+ so.depends('ndp', 'hybrid');
+
+ so = ss.taboption('ipv6', form.Flag, 'ndproxy_slave', _('NDP-Proxy slave'), _('Set interface as NDP-Proxy external slave. Default is off.'));
+ so.depends({ ndp: 'relay', master: '0' });
+ so.depends({ ndp: 'hybrid', master: '0' });
}
ifc.renderFormOptions(s);
+ // Common interface options
+ o = nettools.replaceOption(s, 'advanced', form.Flag, 'defaultroute', _('Use default gateway'), _('If unchecked, no default route is configured'));
+ o.default = o.enabled;
+
+ if (protoval != 'static') {
+ o = nettools.replaceOption(s, 'advanced', form.Flag, 'peerdns', _('Use DNS servers advertised by peer'), _('If unchecked, the advertised DNS server addresses are ignored'));
+ o.default = o.enabled;
+ }
+
+ o = nettools.replaceOption(s, 'advanced', form.DynamicList, 'dns', _('Use custom DNS servers'));
+ if (protoval != 'static')
+ o.depends('peerdns', '0');
+ o.datatype = 'ipaddr';
+
+ o = nettools.replaceOption(s, 'advanced', form.DynamicList, 'dns_search', _('DNS search domains'));
+ if (protoval != 'static')
+ o.depends('peerdns', '0');
+ o.datatype = 'hostname';
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'dns_metric', _('DNS weight'), _('The DNS server entries in the local resolv.conf are primarily sorted by the weight specified here'));
+ o.datatype = 'uinteger';
+ o.placeholder = '0';
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'metric', _('Use gateway metric'));
+ o.datatype = 'uinteger';
+ o.placeholder = '0';
+
+ o = nettools.replaceOption(s,'advanced', form.ListValue, 'multipath', _('Multipath setting'), _('Only one interface must be set as Master.'));
+ o.value('on',_('Enabled'));
+ o.value('off',_('Disabled'));
+ o.value('master',_('Master'));
+ o.value('backup',_('Backup'));
+ o.default = 'off';
+
+ o = nettools.replaceOption(s,'advanced', form.Value, 'addlatency', _('Additional latency'));
+ o.datatype = 'uinteger';
+ o.default = '0';
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'ip4table', _('Override IPv4 routing table'));
+ o.datatype = 'or(uinteger, string)';
+ for (var i = 0; i < rtTables.length; i++)
+ o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6table', _('Override IPv6 routing table'));
+ o.datatype = 'or(uinteger, string)';
+ for (var i = 0; i < rtTables.length; i++)
+ o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][0], rtTables[i][1]));
+
+ o = nettools.replaceOption(s, 'advanced', form.Flag, 'delegate', _('Delegate IPv6 prefixes'), _('Enable downstream delegation of IPv6 prefixes available on this interface'));
+ o.default = o.enabled;
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6assign', _('IPv6 assignment length'), _('Assign a part of given length of every public IPv6-prefix to this interface'));
+ o.value('', _('disabled'));
+ o.value('64');
+ o.datatype = 'max(128)';
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6hint', _('IPv6 assignment hint'), _('Assign prefix parts using this hexadecimal subprefix ID for this interface.'));
+ o.placeholder = '0';
+ o.validate = function(section_id, value) {
+ if (value == null || value == '')
+ return true;
+
+ var n = parseInt(value, 16);
+
+ if (!/^(0x)?[0-9a-fA-F]+$/.test(value) || isNaN(n) || n >= 0xffffffff)
+ return _('Expecting a hexadecimal assignment hint');
+
+ return true;
+ };
+ for (var i = 33; i <= 64; i++)
+ o.depends('ip6assign', String(i));
+
+
+ o = nettools.replaceOption(s, 'advanced', form.DynamicList, 'ip6class', _('IPv6 prefix filter'), _('If set, downstream subnets are only allocated from the given IPv6 prefix classes.'));
+ o.value('local', 'local (%s)'.format(_('Local ULA')));
+
+ var prefixClasses = {};
+
+ this.networks.forEach(function(net) {
+ var prefixes = net._ubus('ipv6-prefix');
+ if (Array.isArray(prefixes)) {
+ prefixes.forEach(function(pfx) {
+ if (L.isObject(pfx) && typeof(pfx['class']) == 'string') {
+ prefixClasses[pfx['class']] = prefixClasses[pfx['class']] || {};
+ prefixClasses[pfx['class']][net.getName()] = true;
+ }
+ });
+ }
+ });
+
+ Object.keys(prefixClasses).sort().forEach(function(c) {
+ var networks = Object.keys(prefixClasses[c]).sort().join(', ');
+ o.value(c, (c != networks) ? '%s (%s)'.format(c, networks) : c);
+ });
+
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6ifaceid', _('IPv6 suffix'), _("Optional. Allowed values: 'eui64', 'random', fixed value like '::1' or '::1:2'. When IPv6 prefix (like 'a:b:c:d::') is received from a delegating server, use the suffix (like '::1') to form the IPv6 address ('a:b:c:d::1') for the interface."));
+ o.datatype = 'ip6hostid';
+ o.placeholder = '::1';
+
+ o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6weight', _('IPv6 preference'), _('When delegating prefixes to multiple downstreams, interfaces with a higher preference value are considered first when allocating subnets.'));
+ o.datatype = 'uinteger';
+ o.placeholder = '0';
+
for (var i = 0; i < s.children.length; i++) {
o = s.children[i];
switch (o.option) {
case 'proto':
- case 'delegate':
case 'auto':
- case 'type':
- case 'stp':
- case 'igmp_snooping':
- case 'ifname_single':
- case 'ifname_multi':
- case 'ifname_master':
case '_dhcp':
case '_zone':
case '_switch_proto':
case '_ifacestat_modal':
continue;
+ case 'igmp_snooping':
+ case 'stp':
+ case 'type':
+ case '_net_device':
+ var deps = [];
+ for (var j = 0; j < protocols.length; j++) {
+ if (!protocols[j].isVirtual()) {
+ if (o.deps.length)
+ for (var k = 0; k < o.deps.length; k++)
+ deps.push(Object.assign({ proto: protocols[j].getProtocol() }, o.deps[k]));
+ else
+ deps.push({ proto: protocols[j].getProtocol() });
+ }
+ }
+ o.deps = deps;
+ break;
+
default:
if (o.deps.length)
for (var j = 0; j < o.deps.length; j++)
@@ -789,14 +1056,28 @@ return view.extend({
o.depends('proto', protoval);
}
}
+
+ this.activeSection = s.section;
}, this));
};
+ s.handleModalCancel = function(/* ... */) {
+ var type = uci.get('network', this.activeSection || this.addedSection, 'type'),
+ device = (type == 'bridge') ? 'br-%s'.format(this.activeSection || this.addedSection) : null;
+
+ uci.sections('network', 'bridge-vlan', function(bvs) {
+ if (device != null && bvs.device == device)
+ uci.remove('network', bvs['.name']);
+ });
+
+ return form.GridSection.prototype.handleModalCancel.apply(this, arguments);
+ };
+
s.handleAdd = function(ev) {
var m2 = new form.Map('network'),
s2 = m2.section(form.NamedSection, '_new_'),
protocols = network.getProtocols(),
- proto, name, type, ifname_single, ifname_multi, ifname_master;
+ proto, name, device;
protocols.sort(function(a, b) {
return a.getProtocol() > b.getProtocol();
@@ -829,35 +1110,15 @@ return view.extend({
proto = s2.option(form.ListValue, 'proto', _('Protocol'));
proto.validate = name.validate;
- type = s2.option(form.ListValue, 'type', _('Interface type'));
- type.value('',_('Normal'));
- type.value('bridge',_('Bridge'));
- type.value('macvlan',_('MacVLAN'));
-
- ifname_single = s2.option(widgets.DeviceSelect, 'ifname_single', _('Interface'));
- ifname_single.noaliases = false;
- ifname_single.optional = false;
-
- ifname_master = s2.option(widgets.DeviceSelect, 'ifname_master', _('Base interface'));
- ifname_master.noaliases = false;
- ifname_master.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()) {
- type.depends({ proto: protocols[i].getProtocol() });
- ifname_single.depends({ type: '', proto: protocols[i].getProtocol() });
- ifname_multi.depends({ type: 'bridge', proto: protocols[i].getProtocol() });
- ifname_master.depends({ type: 'macvlan', proto: protocols[i].getProtocol() });
- }
+ if (!protocols[i].isVirtual())
+ device.depends('proto', protocols[i].getProtocol());
}
m2.render().then(L.bind(function(nodes) {
@@ -873,7 +1134,7 @@ return view.extend({
'click': ui.createHandlerFn(this, function(ev) {
var nameval = name.isValid('_new_') ? name.formvalue('_new_') : null,
protoval = proto.isValid('_new_') ? proto.formvalue('_new_') : null,
- protoclass = protoval ? network.getProtocol(protoval) : null;
+ protoclass = protoval ? network.getProtocol(protoval, nameval) : null;
if (nameval == null || protoval == null || nameval == '' || protoval == '')
return;
@@ -889,22 +1150,11 @@ return view.extend({
return m.save(function() {
var section_id = uci.add('network', 'interface', nameval);
- uci.set('network', section_id, 'proto', protoval);
+ protoclass.set('proto', protoval);
+ protoclass.addDevice(device.formvalue('_new_'));
- if (ifname_single.isActive('_new_')) {
- uci.set('network', section_id, 'ifname', ifname_single.formvalue('_new_'));
- }
- else if (ifname_multi.isActive('_new_')) {
- uci.set('network', section_id, 'type', 'bridge');
- uci.set('network', section_id, 'ifname', L.toArray(ifname_multi.formvalue('_new_')).join(' '));
- }
- else if (ifname_master.isActive('_new_')) {
- uci.set('network', section_id, 'type', 'macvlan');
- uci.set('network', section_id, 'ifname', section_id);
- uci.set('network', section_id, 'masterintf', L.toArray(ifname_master.formvalue('_new_')).join(' '));
- }
+ m.children[0].addedSection = section_id;
}).then(L.bind(m.children[0].renderMoreOptionsModal, m.children[0], nameval));
-
});
})
}, _('Create interface'))
@@ -981,11 +1231,218 @@ return view.extend({
};
+ // Device configuration
+ s = m.section(form.GridSection, 'device', _('Devices'));
+ s.addremove = true;
+ s.anonymous = true;
+ s.addbtntitle = _('Add device configuration…');
+
+ s.cfgsections = function() {
+ var sections = uci.sections('network', 'device'),
+ section_ids = sections.sort(function(a, b) { return a.name > b.name }).map(function(s) { return s['.name'] });
+
+ for (var i = 0; i < netDevs.length; i++) {
+ if (sections.filter(function(s) { return s.name == netDevs[i].getName() }).length)
+ continue;
+
+ if (netDevs[i].getType() == 'wifi' && !netDevs[i].isUp())
+ continue;
+
+ /* Unless http://lists.openwrt.org/pipermail/openwrt-devel/2020-July/030397.html is implemented,
+ we cannot properly redefine bridges as devices, so filter them away for now... */
+
+ var m = netDevs[i].isBridge() ? netDevs[i].getName().match(/^br-([A-Za-z0-9_]+)$/) : null,
+ s = m ? uci.get('network', m[1]) : null;
+
+ if (s && s['.type'] == 'interface' && s.type == 'bridge')
+ continue;
+
+ section_ids.push('dev:%s'.format(netDevs[i].getName()));
+ }
+
+ return section_ids;
+ };
+
+ s.renderMoreOptionsModal = function(section_id, ev) {
+ var m = section_id.match(/^dev:(.+)$/);
+
+ if (m) {
+ var devtype = getDevType(section_id);
+
+ section_id = uci.add('network', 'device');
+
+ uci.set('network', section_id, 'name', m[1]);
+ uci.set('network', section_id, 'type', (devtype != 'ethernet') ? devtype : null);
+
+ this.addedSection = section_id;
+ }
+
+ return this.super('renderMoreOptionsModal', [section_id, ev]);
+ };
+
+ s.renderRowActions = function(section_id) {
+ var trEl = this.super('renderRowActions', [ section_id, _('Configure…') ]),
+ 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;
+ };
+
+ s.modaltitle = function(section_id) {
+ var m = section_id.match(/^dev:(.+)$/),
+ name = m ? m[1] : uci.get('network', section_id, 'name');
+
+ return name ? '%s: %q'.format(getDevTypeDesc(section_id), name) : _('Add device configuration');
+ };
+
+ s.addModalOptions = function(s) {
+ var isNew = (uci.get('network', s.section, 'name') == null),
+ dev = getDevice(s.section);
+
+ nettools.addDeviceOptions(s, dev, isNew);
+ };
+
+ s.handleModalCancel = function(map /*, ... */) {
+ var name = uci.get('network', this.addedSection, 'name')
+
+ uci.sections('network', 'bridge-vlan', function(bvs) {
+ if (name != null && bvs.device == name)
+ uci.remove('network', bvs['.name']);
+ });
+
+ if (map.addedVLANs)
+ for (var i = 0; i < map.addedVLANs.length; i++)
+ uci.remove('network', map.addedVLANs[i]);
+
+ return form.GridSection.prototype.handleModalCancel.apply(this, arguments);
+ };
+
+ function getDevice(section_id) {
+ var m = section_id.match(/^dev:(.+)$/),
+ name = m ? m[1] : uci.get('network', section_id, 'name');
+
+ return netDevs.filter(function(d) { return d.getName() == name })[0];
+ }
+
+ function getDevType(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 (type) {
+ case '':
+ return null;
+
+ case 'vlan':
+ case '8021q':
+ return '8021q';
+
+ case '8021ad':
+ return '8021ad';
+
+ case 'bridge':
+ return 'bridge';
+
+ case 'tunnel':
+ return 'tunnel';
+
+ case 'macvlan':
+ return 'macvlan';
+
+ case 'veth':
+ return 'veth';
+
+ case 'wifi':
+ case 'alias':
+ case 'switch':
+ case 'ethernet':
+ default:
+ return 'ethernet';
+ }
+ }
+
+ function getDevTypeDesc(section_id) {
+ switch (getDevType(section_id) || '') {
+ case '':
+ return E('em', [ _('Device not present') ]);
+
+ case '8021q':
+ return _('VLAN (802.1q)');
+
+ case '8021ad':
+ return _('VLAN (802.1ad)');
+
+ case 'bridge':
+ return _('Bridge device');
+
+ case 'tunnel':
+ return _('Tunnel device');
+
+ case 'macvlan':
+ return _('MAC VLAN');
+
+ case 'veth':
+ return _('Virtual Ethernet');
+
+ default:
+ return _('Network device');
+ }
+ }
+
+ o = s.option(form.DummyValue, 'name', _('Device'));
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var dev = getDevice(section_id),
+ ext = section_id.match(/^dev:/),
+ icon = render_iface(dev);
+
+ if (ext)
+ icon.querySelector('img').style.opacity = '.5';
+
+ return E('span', { 'class': 'ifacebadge' }, [
+ icon,
+ E('span', { 'style': ext ? 'opacity:.5' : null }, [
+ dev ? dev.getName() : (uci.get('network', section_id, 'name') || '?')
+ ])
+ ]);
+ };
+
+ o = s.option(form.DummyValue, 'type', _('Type'));
+ o.textvalue = getDevTypeDesc;
+ o.modalonly = false;
+
+ o = s.option(form.DummyValue, 'macaddr', _('MAC Address'));
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var dev = getDevice(section_id),
+ val = uci.get('network', section_id, 'macaddr'),
+ mac = dev ? dev.getMAC() : null;
+
+ return val ? E('strong', {
+ 'data-tooltip': _('The value is overridden by configuration. Original: %s').format(mac || _('unknown'))
+ }, [ val.toUpperCase() ]) : (mac || '-');
+ };
+
+ o = s.option(form.DummyValue, 'mtu', _('MTU'));
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var dev = getDevice(section_id),
+ val = uci.get('network', section_id, 'mtu'),
+ mtu = dev ? dev.getMTU() : null;
+
+ return val ? E('strong', {
+ 'data-tooltip': _('The value is overridden by configuration. Original: %s').format(mtu || _('unknown'))
+ }, [ val ]) : (mtu || '-').toString();
+ };
+
s = m.section(form.TypedSection, 'globals', _('Global network options'));
s.addremove = false;
s.anonymous = true;
- o = s.option(form.Value, 'ula_prefix', _('IPv6 ULA-Prefix'));
+ o = s.option(form.Value, 'ula_prefix', _('IPv6 ULA-Prefix'), _('Unique Local Address - in the range fc00::/7
. Typically only within the ‘local’ half fd00::/8
. ULA for IPv6 is analogous to IPv4 private network addressing. This prefix is randomly generated at first install.'));
o.datatype = 'cidr6';
o = s.option(form.Flag, 'packet_steering', _('Packet Steering'), _('Enable packet steering across all CPUs. May help or hinder network speed.'));
diff --git a/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js b/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js
index b218daac3..7e11a3cb4 100644
--- a/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js
+++ b/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js
@@ -20,6 +20,7 @@ return view.extend({
s.anonymous = true;
s.addremove = true;
s.sortable = true;
+ s.nodescriptions = true;
s.tab('general', _('General Settings'));
s.tab('advanced', _('Advanced Settings'));
@@ -28,6 +29,10 @@ return view.extend({
o.rmempty = false;
o.nocreate = true;
+ o = s.taboption('general', form.Flag, 'disabled', _('Disable'), _('Disable this route'));
+ o.rmempty = true;
+ o.default = o.disabled;
+
o = s.taboption('general', form.Value, 'target', _('Target'), (i == 4) ? _('Host-IP or Network') : _('IPv6 -Address or Network (CIDR)'));
o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr';
o.rmempty = false;
diff --git a/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js b/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js
index d19b025e3..5115a69eb 100644
--- a/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js
+++ b/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js
@@ -199,7 +199,9 @@ function format_wifirate(rate) {
var s = '%.1f\xa0%s, %d\xa0%s'.format(rate.rate / 1000, _('Mbit/s'), rate.mhz, _('MHz')),
ht = rate.ht, vht = rate.vht,
mhz = rate.mhz, nss = rate.nss,
- mcs = rate.mcs, sgi = rate.short_gi;
+ mcs = rate.mcs, sgi = rate.short_gi,
+ he = rate.he, he_gi = rate.he_gi,
+ he_dcm = rate.he_dcm;
if (ht || vht) {
if (vht) s += ', VHT-MCS\xa0%d'.format(mcs);
@@ -208,6 +210,13 @@ function format_wifirate(rate) {
if (sgi) s += ', ' + _('Short GI').replace(/ /g, '\xa0');
}
+ if (he) {
+ s += ', HE-MCS\xa0%d'.format(mcs);
+ if (nss) s += ', HE-NSS\xa0%d'.format(nss);
+ if (he_gi) s += ', HE-GI\xa0%d'.format(he_gi);
+ if (he_dcm) s += ', HE-DCM\xa0%d'.format(he_dcm);
+ }
+
return s;
}
@@ -303,16 +312,32 @@ var CBIWifiFrequencyValue = form.Value.extend({
this.callFrequencyList(section_id)
]).then(L.bind(function(data) {
this.channels = {
- '11g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
- '11a': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : []
+ '2g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
+ '5g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
+ '6g': [],
+ '60g': []
};
- for (var i = 0; i < data[1].length; i++)
- this.channels[(data[1][i].mhz > 2484) ? '11a' : '11g'].push(
+ for (var i = 0; i < data[1].length; i++) {
+ var band;
+
+ if (data[1][i].mhz >= 2412 && data[1][i].mhz <= 2484)
+ band = '2g';
+ else if (data[1][i].mhz >= 5160 && data[1][i].mhz <= 5885)
+ band = '5g';
+ else if (data[1][i].mhz >= 5925 && data[1][i].mhz <= 7125)
+ band = '6g';
+ else if (data[1][i].mhz >= 58329 && data[1][i].mhz <= 69120)
+ band = '60g';
+ else
+ continue;
+
+ this.channels[band].push(
data[1][i].channel,
'%d (%d Mhz)'.format(data[1][i].channel, data[1][i].mhz),
!data[1][i].restricted
);
+ }
var hwmodelist = L.toArray(data[0] ? data[0].getHWModes() : null)
.reduce(function(o, v) { o[v] = true; return o }, {});
@@ -320,7 +345,8 @@ var CBIWifiFrequencyValue = form.Value.extend({
this.modes = [
'', 'Legacy', true,
'n', 'N', hwmodelist.n,
- 'ac', 'AC', hwmodelist.ac
+ 'ac', 'AC', hwmodelist.ac,
+ 'ax', 'AX', hwmodelist.ax
];
var htmodelist = L.toArray(data[0] ? data[0].getHTModes() : null)
@@ -337,20 +363,30 @@ var CBIWifiFrequencyValue = form.Value.extend({
'VHT40', '40 MHz', htmodelist.VHT40,
'VHT80', '80 MHz', htmodelist.VHT80,
'VHT160', '160 MHz', htmodelist.VHT160
+ ],
+ 'ax': [
+ 'HE20', '20 MHz', htmodelist.HE20,
+ 'HE40', '40 MHz', htmodelist.HE40,
+ 'HE80', '80 MHz', htmodelist.HE80,
+ 'HE160', '160 MHz', htmodelist.HE160
]
};
this.bands = {
'': [
- '11g', '2.4 GHz', this.channels['11g'].length > 3,
- '11a', '5 GHz', this.channels['11a'].length > 3
+ '2g', '2.4 GHz', this.channels['2g'].length > 3,
+ '5g', '5 GHz', this.channels['5g'].length > 3
],
'n': [
- '11g', '2.4 GHz', this.channels['11g'].length > 3,
- '11a', '5 GHz', this.channels['11a'].length > 3
+ '2g', '2.4 GHz', this.channels['2g'].length > 3,
+ '5g', '5 GHz', this.channels['5g'].length > 3
],
'ac': [
- '11a', '5 GHz', true
+ '5g', '5 GHz', true
+ ],
+ 'ax': [
+ '2g', '2.4 GHz', this.channels['2g'].length > 3,
+ '5g', '5 GHz', this.channels['5g'].length > 3
]
};
}, this));
@@ -392,6 +428,8 @@ var CBIWifiFrequencyValue = form.Value.extend({
this.setValues(band, this.bands[mode.value]);
this.toggleWifiChannel(elem);
+
+ this.map.checkDepends();
},
toggleWifiChannel: function(elem) {
@@ -408,11 +446,14 @@ var CBIWifiFrequencyValue = form.Value.extend({
bwdt = elem.querySelector('.htmode'),
htval = uci.get('wireless', section_id, 'htmode'),
hwval = uci.get('wireless', section_id, 'hwmode'),
- chval = uci.get('wireless', section_id, 'channel');
+ chval = uci.get('wireless', section_id, 'channel'),
+ bandval = uci.get('wireless', section_id, 'band');
this.setValues(mode, this.modes);
- if (/VHT20|VHT40|VHT80|VHT160/.test(htval))
+ if (/HE20|HE40|HE80|HE160/.test(htval))
+ mode.value = 'ax';
+ else if (/VHT20|VHT40|VHT80|VHT160/.test(htval))
mode.value = 'ac';
else if (/HT20|HT40/.test(htval))
mode.value = 'n';
@@ -421,15 +462,24 @@ var CBIWifiFrequencyValue = form.Value.extend({
this.toggleWifiMode(elem);
- if (/a/.test(hwval))
- band.value = '11a';
- else
- band.value = '11g';
+ if (hwval != null) {
+ this.useBandOption = false;
+
+ if (/a/.test(hwval))
+ band.value = '5g';
+ else
+ band.value = '2g';
+ }
+ else {
+ this.useBandOption = true;
+
+ band.value = bandval;
+ }
this.toggleWifiBand(elem);
bwdt.value = htval;
- chan.value = chval;
+ chan.value = chval || chan.options[0].value;
return elem;
},
@@ -461,6 +511,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
E('select', {
'class': 'channel',
'style': 'width:auto',
+ 'change': L.bind(this.map.checkDepends, this.map),
'disabled': (this.disabled != null) ? this.disabled : this.map.readonly
})
]),
@@ -469,6 +520,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
E('select', {
'class': 'htmode',
'style': 'width:auto',
+ 'change': L.bind(this.map.checkDepends, this.map),
'disabled': (this.disabled != null) ? this.disabled : this.map.readonly
})
]),
@@ -481,7 +533,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
cfgvalue: function(section_id) {
return [
uci.get('wireless', section_id, 'htmode'),
- uci.get('wireless', section_id, 'hwmode'),
+ uci.get('wireless', section_id, 'hwmode') || uci.get('wireless', section_id, 'band'),
uci.get('wireless', section_id, 'channel')
];
},
@@ -498,7 +550,12 @@ var CBIWifiFrequencyValue = form.Value.extend({
write: function(section_id, value) {
uci.set('wireless', section_id, 'htmode', value[0] || null);
- uci.set('wireless', section_id, 'hwmode', value[1]);
+
+ if (this.useBandOption)
+ uci.set('wireless', section_id, 'band', value[1]);
+ else
+ uci.set('wireless', section_id, 'hwmode', (value[1] == '2g') ? '11g' : '11a');
+
uci.set('wireless', section_id, 'channel', value[2]);
}
});
@@ -883,6 +940,9 @@ return view.extend({
o.ucisection = s.section;
if (hwtype == 'mac80211') {
+ o = ss.taboption('general', form.Flag, 'legacy_rates', _('Allow legacy 802.11b rates'), _('Legacy or badly behaving devices may require legacy 802.11b rates to interoperate. Airtime efficiency may be significantly reduced where these are used. It is recommended to not allow 802.11b rates where possible.'));
+ o.depends({'_freq': '11g', '!contains': true});
+
o = ss.taboption('general', CBIWifiTxPowerValue, 'txpower', _('Maximum transmit power'), _('Specifies the maximum transmit power the wireless radio may use. Depending on regulatory requirements and wireless usage, the actual transmit power may be reduced by the driver.'));
o.wifiNetwork = radioNet;
@@ -895,9 +955,6 @@ return view.extend({
o.value('2', _('High'));
o.value('3', _('Very High'));
- o = ss.taboption('advanced', form.Flag, 'legacy_rates', _('Allow legacy 802.11b rates'));
- o.default = o.enabled;
-
o = ss.taboption('advanced', form.Value, 'distance', _('Distance Optimization'), _('Distance to farthest network member in meters.'));
o.datatype = 'or(range(0,114750),"auto")';
o.placeholder = 'auto';
@@ -983,8 +1040,17 @@ return view.extend({
return net || network.addNetwork(name, { proto: 'none' });
}, this, values[i])).then(L.bind(function(dev, net) {
if (net) {
- if (!net.isEmpty())
- net.set('type', 'bridge');
+ if (!net.isEmpty()) {
+ var target_dev = net.getDevice();
+
+ /* Resolve parent interface of vlan */
+ while (target_dev && target_dev.getType() == 'vlan')
+ target_dev = target_dev.getParent();
+
+ if (!target_dev || target_dev.getType() != 'bridge')
+ net.set('type', 'bridge');
+ }
+
net.addDevice(dev);
}
}, this, dev)));
@@ -1014,7 +1080,7 @@ return view.extend({
bssid.depends('mode', 'sta');
bssid.depends('mode', 'sta-wds');
- o = ss.taboption('macfilter', form.ListValue, 'macfilter', _('MAC-Address Filter'));
+ o = ss.taboption('macfilter', form.ListValue, 'macfilter', _('MAC Address Filter'));
o.depends('mode', 'ap');
o.depends('mode', 'ap-wds');
o.value('', _('disable'));
@@ -1069,11 +1135,11 @@ return view.extend({
return mode;
};
- o = ss.taboption('general', form.Flag, 'hidden', _('Hide ESSID '));
+ o = ss.taboption('general', form.Flag, 'hidden', _('Hide ESSID '), _('Where the ESSID is hidden, clients may fail to roam and airtime efficiency may be significantly reduced.'));
o.depends('mode', 'ap');
o.depends('mode', 'ap-wds');
- o = ss.taboption('general', form.Flag, 'wmm', _('WMM Mode'));
+ o = ss.taboption('general', form.Flag, 'wmm', _('WMM Mode'), _('Where Wi-Fi Multimedia (WMM) Mode QoS is disabled, clients may be limited to 802.11a/802.11g rates.'));
o.depends('mode', 'ap');
o.depends('mode', 'ap-wds');
o.default = o.enabled;
@@ -1609,34 +1675,32 @@ return view.extend({
if (hwtype == 'mac80211') {
// ieee802.11w options
- if (L.hasSystemFeature('hostapd', '11w')) {
- o = ss.taboption('encryption', form.ListValue, 'ieee80211w', _('802.11w Management Frame Protection'), _("Requires the 'full' version of wpad/hostapd and support from the wifi driver (as of Jan 2019: ath9k, ath10k, mwlwifi and mt76)"));
- o.value('', _('Disabled'));
- o.value('1', _('Optional'));
- o.value('2', _('Required'));
- add_dependency_permutations(o, { mode: ['ap', 'ap-wds', 'sta', 'sta-wds'], encryption: ['owe', 'psk2', 'psk-mixed', 'sae', 'sae-mixed', 'wpa2', 'wpa3', 'wpa3-mixed'] });
+ o = ss.taboption('encryption', form.ListValue, 'ieee80211w', _('802.11w Management Frame Protection'), _("Note: Some wireless drivers do not fully support 802.11w. E.g. mwlwifi may have problems"));
+ o.value('', _('Disabled'));
+ o.value('1', _('Optional'));
+ o.value('2', _('Required'));
+ add_dependency_permutations(o, { mode: ['ap', 'ap-wds', 'sta', 'sta-wds'], encryption: ['owe', 'psk2', 'psk-mixed', 'sae', 'sae-mixed', 'wpa2', 'wpa3', 'wpa3-mixed'] });
- o.defaults = {
- '2': [{ encryption: 'sae' }, { encryption: 'owe' }, { encryption: 'wpa3' }, { encryption: 'wpa3-mixed' }],
- '1': [{ encryption: 'sae-mixed'}],
- '': []
- };
-
- o = ss.taboption('encryption', form.Value, 'ieee80211w_max_timeout', _('802.11w maximum timeout'), _('802.11w Association SA Query maximum timeout'));
- o.depends('ieee80211w', '1');
- o.depends('ieee80211w', '2');
- o.datatype = 'uinteger';
- o.placeholder = '1000';
- o.rmempty = true;
-
- o = ss.taboption('encryption', form.Value, 'ieee80211w_retry_timeout', _('802.11w retry timeout'), _('802.11w Association SA Query retry timeout'));
- o.depends('ieee80211w', '1');
- o.depends('ieee80211w', '2');
- o.datatype = 'uinteger';
- o.placeholder = '201';
- o.rmempty = true;
+ o.defaults = {
+ '2': [{ encryption: 'sae' }, { encryption: 'owe' }, { encryption: 'wpa3' }, { encryption: 'wpa3-mixed' }],
+ '1': [{ encryption: 'sae-mixed'}],
+ '': []
};
+ o = ss.taboption('encryption', form.Value, 'ieee80211w_max_timeout', _('802.11w maximum timeout'), _('802.11w Association SA Query maximum timeout'));
+ o.depends('ieee80211w', '1');
+ o.depends('ieee80211w', '2');
+ o.datatype = 'uinteger';
+ o.placeholder = '1000';
+ o.rmempty = true;
+
+ o = ss.taboption('encryption', form.Value, 'ieee80211w_retry_timeout', _('802.11w retry timeout'), _('802.11w Association SA Query retry timeout'));
+ o.depends('ieee80211w', '1');
+ o.depends('ieee80211w', '2');
+ o.datatype = 'uinteger';
+ o.placeholder = '201';
+ o.rmempty = true;
+
o = ss.taboption('encryption', form.Flag, 'wpa_disable_eapol_key_retries', _('Enable key reinstallation (KRACK) countermeasures'), _('Complicates key reinstallation attacks on the client side by disabling retransmission of EAPOL-Key frames that are used to install keys. This workaround might cause interoperability issues and reduced robustness of key negotiation especially in environments with heavy traffic load.'));
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk2', 'psk-mixed', 'sae', 'sae-mixed', 'wpa2', 'wpa3', 'wpa3-mixed'] });
@@ -2082,7 +2146,7 @@ return view.extend({
var table = E('table', { 'class': 'table assoclist', 'id': 'wifi_assoclist_table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th nowrap' }, _('Network')),
- E('th', { 'class': 'th hide-xs' }, _('MAC-Address')),
+ E('th', { 'class': 'th hide-xs' }, _('MAC address')),
E('th', { 'class': 'th' }, _('Host')),
E('th', { 'class': 'th' }, _('Signal / Noise')),
E('th', { 'class': 'th' }, _('RX Rate / TX Rate'))
diff --git a/luci-mod-network/root/usr/share/rpcd/acl.d/luci-mod-network.json b/luci-mod-network/root/usr/share/rpcd/acl.d/luci-mod-network.json
index d6c84bab2..6943d9563 100644
--- a/luci-mod-network/root/usr/share/rpcd/acl.d/luci-mod-network.json
+++ b/luci-mod-network/root/usr/share/rpcd/acl.d/luci-mod-network.json
@@ -4,7 +4,11 @@
"read": {
"cgi-io": [ "exec" ],
"file": {
- "/usr/libexec/luci-peeraddr": [ "exec" ]
+ "/etc/iproute2/rt_tables": [ "read" ],
+ "/proc/sys/net/ipv6/conf/*/mtu": [ "read" ],
+ "/proc/sys/net/ipv6/conf/*/hop_limit": [ "read" ],
+ "/usr/libexec/luci-peeraddr": [ "exec" ],
+ "/usr/lib/opkg/info/netifd.control": [ "read" ]
},
"ubus": {
"file": [ "exec" ],
diff --git a/mlvpn/files/etc/init.d/mlvpn b/mlvpn/files/etc/init.d/mlvpn
index 6ef4bfdc6..33f6e75a9 100755
--- a/mlvpn/files/etc/init.d/mlvpn
+++ b/mlvpn/files/etc/init.d/mlvpn
@@ -13,7 +13,8 @@ interface_multipath_settings() {
mode="$(uci -q get openmptcprouter.$config.multipath)"
}
[ "$mode" = "off" ] || [ "$mode" = "" ] && return 1
- config_get ifname "$config" ifname
+ config_get ifname "$config" device
+ [ -z "$ifname" ] && config_get ifname "$config" ifname
[ -z "$ifname" ] && ifname=$(ifstatus "$config" | jsonfilter -q -e '@["l3_device"]')
[ -n "$(echo $ifname | grep '@')" ] && ifname=$(ifstatus "$1" | jsonfilter -q -e '@["device"]')
[ -z "$ifname" ] && return 1
@@ -46,7 +47,7 @@ start() {
firstport="$(uci -q get mlvpn.general.firstport)"
if [ "$(uci -q get network.omrvpn)" != "${interface_name}" ]; then
- uci -q set network.omrvpn.ifname=${interface_name}
+ uci -q set network.omrvpn.device=${interface_name}
uci -q commit
fi
diff --git a/mlvpn/files/etc/uci-defaults/4100-mlvpn b/mlvpn/files/etc/uci-defaults/4100-mlvpn
index 45d4f57ee..8aa0a6139 100644
--- a/mlvpn/files/etc/uci-defaults/4100-mlvpn
+++ b/mlvpn/files/etc/uci-defaults/4100-mlvpn
@@ -11,7 +11,7 @@ if [ "$(uci -q get network.omrvpn)" = "" ] && [ "$(uci -q get network.mlvpn)" =
uci -q batch <<-EOF >/dev/null
delete network.mlvpn=interface
set network.mlvpn=interface
- set network.mlvpn.ifname=mlvpn0
+ set network.mlvpn.device=mlvpn0
set network.mlvpn.proto=dhcp
set network.mlvpn.ip4table=vpn
set network.mlvpn.multipath=off
diff --git a/mptcp/files/etc/init.d/mptcp b/mptcp/files/etc/init.d/mptcp
index 334cc0632..432268ff2 100755
--- a/mptcp/files/etc/init.d/mptcp
+++ b/mptcp/files/etc/init.d/mptcp
@@ -85,7 +85,8 @@ interface_multipath_settings() {
local enabled
config_get enabled "$config" auto "1"
- config_get iface "$config" ifname
+ config_get iface "$config" device
+ [ -z "$iface" ] && config_get iface "$config" ifname
config_get txqueuelen "$config" txqueuelen
[ -z "$iface" ] && iface=$(ifstatus "$config" | jsonfilter -q -e '@["l3_device"]')
[ -n "$(echo $iface | grep '@')" ] && iface=$(ifstatus "$config" | jsonfilter -q -e '@["device"]')
@@ -349,7 +350,8 @@ interface_multipath_settings() {
}
load_interfaces() {
- config_get ifname "$1" ifname
+ config_get ifname "$1" device
+ [ -z "$ifname" ] && config_get ifname "$1" ifname
config_get multipath "$1" multipath ""
[ -z "$multipath" ] && multipath="$(uci -q get openmptcprouter.$1.multipath)"
[ "$multipath" != "off" ] && [ "$multipath" != "" ] && interfaces=" ${ifname} ${interfaces}"
diff --git a/mptcp/files/usr/share/omr/post-tracking.d/post-tracking b/mptcp/files/usr/share/omr/post-tracking.d/post-tracking
index c764e794d..e26091d45 100755
--- a/mptcp/files/usr/share/omr/post-tracking.d/post-tracking
+++ b/mptcp/files/usr/share/omr/post-tracking.d/post-tracking
@@ -15,6 +15,7 @@ set_route() {
interface_if=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
interface_up=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.ifname)
[ -n "$(echo $interface_if | grep '@')" ] && interface_if=$(ifstatus "${INTERFACE}" | jsonfilter -q -e '@["device"]')
interface_current_config=$(uci -q get openmptcprouter.$INTERFACE.state || echo "up")
@@ -52,6 +53,7 @@ set_route6() {
interface_if=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
interface_up=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.ifname)
[ -n "$(echo $interface_if | grep '@')" ] && interface_if=$(ifstatus "$INTERFACE" | jsonfilter -q -e '@["device"]')
interface_current_config=$(uci -q get openmptcprouter.$INTERFACE.state || echo "up")
@@ -165,6 +167,7 @@ set_routes_intf() {
}
interface_if=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.ifname)
[ -n "$(echo $interface_if | grep '@')" ] && ifname=$(ifstatus "$INTERFACE" | jsonfilter -q -e '@["device"]')
interface_up=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
@@ -219,6 +222,7 @@ set_routes_intf6() {
}
interface_if=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${INTERFACE}_6" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.ifname)
[ -n "$(echo $interface_if | grep '@')" ] && interface_if=$(ifstatus "$INTERFACE" | jsonfilter -q -e '@["device"]')
interface_up=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
@@ -289,6 +293,7 @@ set_route_balancing() {
}
interface_if=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.ifname)
[ -n "$(echo $interface_if | grep '@')" ] && interface_if=$(ifstatus "$INTERFACE" | jsonfilter -q -e '@["device"]')
interface_up=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
@@ -337,6 +342,7 @@ set_route_balancing6() {
}
interface_if=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(uci -q get network.$INTERFACE.ifname)
[ -n "$(echo $interface_if | grep '@')" ] && interface_if=$(ifstatus "$INTERFACE" | jsonfilter -q -e '@["device"]')
interface_up=$(ifstatus "$INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
@@ -398,10 +404,11 @@ set_server_all_routes() {
[ -n "$serverip" ] && serverip="$(resolveip -4 -t 5 $serverip | head -n 1 | tr -d '\n')"
config_get disabled $server disabled
[ "$disabled" = "1" ] && return
- interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
+ interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${OMR_TRACKER_INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" | jsonfilter -q -e '@["device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
interface_up=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
multipath_config_route=$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.multipath || echo "off")
[ "$multipath_config_route" ] && multipath_config_route=$(uci -q get network.$OMR_TRACKER_INTERFACE.multipath || echo 'off')
@@ -443,10 +450,11 @@ set_server_all_routes6() {
[ -n "$serverip" ] && serverip="$(resolveip -6 -t 5 $serverip | head -n 1 | tr -d '\n')"
config_get disabled $server disabled
[ "$disabled" = "1" ] && return
- interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
+ interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${OMR_TRACKER_INTERFACE}_6" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" | jsonfilter -q -e '@["device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
interface_up=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
multipath_config_route=$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.multipath || echo "off")
[ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.multipathvpn)" = "1" ] && {
@@ -497,10 +505,11 @@ set_server_route() {
[ "$(uci -q get openmptcprouter.settings.mptcpovervpn)" = "openvpn" ] && multipath_config_route="$(uci -q get openmptcprouter.ovpn${OMR_TRACKER_INTERFACE}.multipath || echo "off")"
[ "$(uci -q get openmptcprouter.settings.mptcpovervpn)" = "wireguard" ] && multipath_config_route="$(uci -q get openmptcprouter.wg${OMR_TRACKER_INTERFACE}.multipath || echo "off")"
}
- interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
+ interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${OMR_TRACKER_INTERFACE}_4" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" | jsonfilter -q -e '@["device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
interface_up=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
#multipath_current_config=$(multipath $interface_if | grep "deactivated")
interface_current_config=$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.state || echo "up")
@@ -532,10 +541,11 @@ set_server_route6() {
[ "$(uci -q get openmptcprouter.settings.mptcpovervpn)" = "openvpn" ] && multipath_config_route="$(uci -q get openmptcprouter.ovpn${OMR_TRACKER_INTERFACE}.multipath || echo "off")"
[ "$(uci -q get openmptcprouter.settings.mptcpovervpn)" = "wireguard" ] && multipath_config_route="$(uci -q get openmptcprouter.wg${OMR_TRACKER_INTERFACE}.multipath || echo "off")"
}
- interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
+ interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.device)
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "${OMR_TRACKER_INTERFACE}_6" 2>/dev/null | jsonfilter -q -e '@["l3_device"]')
[ -z "$interface_if" ] && interface_if=$(ifstatus "$OMR_TRACKER_INTERFACE" | jsonfilter -q -e '@["device"]')
+ [ -z "$interface_if" ] && interface_if=$(uci -q get network.$OMR_TRACKER_INTERFACE.ifname)
interface_up=$(ifstatus "$OMR_TRACKER_INTERFACE" 2>/dev/null | jsonfilter -q -e '@["up"]')
#multipath_current_config=$(multipath $interface_if | grep "deactivated")
interface_current_config=$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.state || echo "up")
@@ -895,7 +905,8 @@ multipath_config=$(uci -q get "openmtpcprouter.$OMR_TRACKER_INTERFACE.multipath"
if [ "$multipath_config" = "master" ]; then
#if ([ "$default_gw" != "$OMR_TRACKER_DEVICE_GATEWAY" ] || [ "$default_gw" = "" ]) && [ "$OMR_TRACKER_DEVICE_GATEWAY" != "" ] && ([ "$(uci -q get openmptcprouter.settings.master)" != "balancing" ] || [ "$(uci -q get openmptcprouter.settings.vpn)" = "mlvpn" ]); then
if ([ "$default_gw" != "$OMR_TRACKER_DEVICE_GATEWAY" ] || [ "$default_gw" = "" ]) && [ "$OMR_TRACKER_DEVICE_GATEWAY" != "" ] && [ "$(uci -q get openmptcprouter.settings.master)" != "balancing" ]; then
- omrvpn_intf=$(uci -q get "network.omrvpn.ifname" || echo "tun")
+ omrvpn_intf=$(uci -q get "network.omrvpn.device" || echo "tun")
+ [ -z "$omrvpn_intf" ] && omrvpn_intf=$(uci -q get "network.omrvpn.ifname" || echo "tun")
if [ -n "$omrvpn_intf" ] && [ "$(ip route show default | awk '/default/ {print $5}' | grep $omrvpn_intf)" = "" ] && [ "$(uci -q get openmptcprouter.settings.defaultgw)" != "0" ]; then
_log "Master up : Replace default route by $OMR_TRACKER_DEVICE_GATEWAY dev $OMR_TRACKER_DEVICE"
ip route replace default scope global nexthop via $OMR_TRACKER_DEVICE_GATEWAY dev $OMR_TRACKER_DEVICE 2>&1 >/dev/null
@@ -908,7 +919,8 @@ if [ "$multipath_config" = "master" ]; then
fi
fi
if ([ "$default_gw6" != "$OMR_TRACKER_DEVICE_GATEWAY6" ] || [ "$default_gw6" = "" ]) && [ "$OMR_TRACKER_DEVICE_GATEWAY6" != "" ] && [ "$(uci -q get openmptcprouter.settings.master)" != "balancing" ]; then
- omrvpn_intf=$(uci -q get "network.omrvpn.ifname" || echo "tun")
+ omrvpn_intf=$(uci -q get "network.omrvpn.device" || echo "tun")
+ [ -z "$omrvpn_intf" ] && omrvpn_intf=$(uci -q get "network.omrvpn.ifname" || echo "tun")
if [ -n "$omrvpn_intf" ] && [ "$(ip route show default | awk '/default/ {print $5}' | grep $omrvpn_intf)" = "" ] && [ "$(uci -q get openmptcprouter.settings.defaultgw)" != "0" ]; then
_log "Master up : Replace default route by $OMR_TRACKER_DEVICE_GATEWAY6 dev $OMR_TRACKER_DEVICE"
ip -6 route replace default scope global nexthop via $OMR_TRACKER_DEVICE_GATEWAY6 dev $OMR_TRACKER_DEVICE 2>&1 >/dev/null
@@ -923,7 +935,8 @@ if [ "$multipath_config" = "master" ]; then
fi
#if [ "$(uci -q get openmptcprouter.settings.master)" = "balancing" ] && [ "$(ip route show default | grep weight)" = "" ] && [ "$(uci -q get openmptcprouter.settings.defaultgw)" != "0" ] && [ "$(uci -q get openmptcprouter.settings.vpn)" != "mlvpn" ]; then
if [ "$(uci -q get openmptcprouter.settings.master)" = "balancing" ] && [ "$(ip route show default | grep weight)" = "" ] && [ "$(uci -q get openmptcprouter.settings.defaultgw)" != "0" ]; then
- omrvpn_intf=$(uci -q get "network.omrvpn.ifname" || echo "tun")
+ omrvpn_intf=$(uci -q get "network.omrvpn.device" || echo "tun")
+ [ -z "$omrvpn_intf" ] && omrvpn_intf=$(uci -q get "network.omrvpn.ifname" || echo "tun")
if [ -n "$omrvpn_intf" ] && [ "$(ip route show default | awk '/default/ {print $5}' | grep $omrvpn_intf)" = "" ]; then
routesbalancing=""
routesbalancingbackup=""
diff --git a/omr-tracker/files/bin/omr-tracker-gre b/omr-tracker/files/bin/omr-tracker-gre
index 5c19e43cc..78fa1aef0 100755
--- a/omr-tracker/files/bin/omr-tracker-gre
+++ b/omr-tracker/files/bin/omr-tracker-gre
@@ -23,7 +23,8 @@ _ping_server() {
_ping_tunnel() {
local name=$1
config_get gateway $1 gateway
- config_get ifname $1 ifname
+ config_get ifname $1 device
+ [ -z "$ifname" ] && config_get ifname $1 ifname
config_get disabled $1 disabled
[ "$(echo $ifname | grep oip)" != "" ] && [ -n "$gateway" ] && [ "$disabled" != "1" ] && {
_ping_server $gateway
diff --git a/omr-tracker/files/etc/init.d/omr-tracker b/omr-tracker/files/etc/init.d/omr-tracker
index 3276316e9..7a09ef82d 100755
--- a/omr-tracker/files/etc/init.d/omr-tracker
+++ b/omr-tracker/files/etc/init.d/omr-tracker
@@ -55,7 +55,7 @@ _launch_tracker() {
local ifname ip4table
ifname=$(ifstatus "$1" | jsonfilter -q -e '@["l3_device"]')
[ -z "$ifname" ] && ifname=$(ifstatus "$1_4" | jsonfilter -q -e '@["l3_device"]')
- [ -z "$ifname" ] && config_get ifname "$1" ifname
+ [ -z "$ifname" ] && config_get ifname "$1" device
[ -n "$(echo $ifname | grep '@')" ] && ifname=$(ifstatus "$1" | jsonfilter -q -e '@["device"]')
config_get multipath "$1" multipath
diff --git a/openmptcprouter-full/Makefile b/openmptcprouter-full/Makefile
index 31282b251..4432da893 100644
--- a/openmptcprouter-full/Makefile
+++ b/openmptcprouter-full/Makefile
@@ -44,7 +44,6 @@ MY_DEPENDS := \
luci-app-uhttpd \
luci-mod-rpc rpcd-mod-rpcsys rpcd-mod-file rpcd-mod-iwinfo \
luci-app-openvpn \
- macvlan \
shadowsocks-libev-ss-server shadowsocks-libev-ss-tunnel \
omr-6in4 ip6tables-mod-nat luci-proto-ipv6 6to4 6in4 6rd ip6tables \
speedtestc \
diff --git a/openmptcprouter/files/etc/init.d/mptcpovervpn b/openmptcprouter/files/etc/init.d/mptcpovervpn
index b36425041..0bb30c0dd 100755
--- a/openmptcprouter/files/etc/init.d/mptcpovervpn
+++ b/openmptcprouter/files/etc/init.d/mptcpovervpn
@@ -68,7 +68,7 @@ mptcp_over_vpn() {
uci -q batch <<-EOF >/dev/null
set network.ovpn${interface}=interface
- set network.ovpn${interface}.ifname="tun${id}"
+ set network.ovpn${interface}.device="tun${id}"
set network.ovpn${interface}.defaultroute='0'
set network.ovpn${interface}.peerdns='0'
set network.ovpn${interface}.proto='none'
diff --git a/openmptcprouter/files/etc/init.d/openmptcprouter-vps b/openmptcprouter/files/etc/init.d/openmptcprouter-vps
index 73eb6d623..71350104c 100755
--- a/openmptcprouter/files/etc/init.d/openmptcprouter-vps
+++ b/openmptcprouter/files/etc/init.d/openmptcprouter-vps
@@ -539,7 +539,7 @@ _get_gre_tunnel() {
set network.oip${i}.label="Tunnel for $publicaddr"
set network.oip${i}.proto=static
set network.oip${i}.nohostroute='1'
- set network.oip${i}.ifname="@oip${i}gre"
+ set network.oip${i}.device="@oip${i}gre"
set network.oip${i}.ipv6='0'
set network.oip${i}.defaultroute='0'
set network.oip${i}.multipath='off'
@@ -823,7 +823,7 @@ _set_vpn_ip() {
local settings
[ -z "$vps_config" ] && vps_config=$(_get_json "config")
[ -z "$vps_config" ] && return
- vpnifname="$(uci -q get network.omrvpn.ifname)"
+ vpnifname="$(uci -q get network.omrvpn.device)"
vpnip_local_current="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.remoteip')"
vpnip_local=$(ip -4 -br addr ls dev ${vpnifname} | awk -F'[ /]+' '{print $3}')
vpnip_remote_current="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.localip')"
@@ -850,7 +850,7 @@ _set_client2client() {
[ -z "$vps_config" ] && vps_config=$(_get_json "config")
[ -z "$vps_config" ] && return
c2cips="$(echo "$vps_config" | jsonfilter -q -e '@.client2client.lanips[0]')"
- vpnifname="$(uci -q get network.omrvpn.ifname)"
+ vpnifname="$(uci -q get network.omrvpn.device)"
vpnip_local=$(ip -4 -br addr ls dev ${vpnifname} | awk -F'[ /]+' '{print $3}' | tr -d "\n")
vpnip_remote=$(ip -4 r list dev ${vpnifname} | grep via | grep -v default | grep -v / | grep -v metric | awk '{print $1}' | tr -d "\n")
for lanip in $c2cips; do
diff --git a/openmptcprouter/files/etc/init.d/openvpnbonding b/openmptcprouter/files/etc/init.d/openvpnbonding
index adad30b5b..f3c085802 100755
--- a/openmptcprouter/files/etc/init.d/openvpnbonding
+++ b/openmptcprouter/files/etc/init.d/openvpnbonding
@@ -77,7 +77,7 @@ start_service()
set network.omrvpn.updelay='20'
set network.omrvpn.use_carrier='1'
set network.omrvpn.mtu='1440'
- set network.omrvpn.ifname= 'bonding-omrvpn'
+ set network.omrvpn.device= 'bonding-omrvpn'
set network.omrvpn.force_link='1'
commit network
EOF
diff --git a/openmptcprouter/files/etc/uci-defaults/1920-omr-network b/openmptcprouter/files/etc/uci-defaults/1920-omr-network
new file mode 100755
index 000000000..fca553290
--- /dev/null
+++ b/openmptcprouter/files/etc/uci-defaults/1920-omr-network
@@ -0,0 +1,303 @@
+#!/bin/sh
+. /lib/functions.sh
+
+_setup_macaddr() {
+ uci -q get "network.$1.macaddr" >/dev/null && return
+ uci -q set "network.$1.macaddr=$2"
+}
+
+_setup_macvlan() {
+ uci -q get "network.$1_dev.ifname" >/dev/null && return
+
+ # do not create macvlan for vlan
+ local _ifname
+ _ifname=$(uci -q get "network.$1.device")
+ case "$_ifname" in
+ eth*.*) return ;;
+ esac
+
+ uci -q batch <<-EOF
+ set network.$1_dev=device
+ set network.$1_dev.name=$1
+ set network.$1_dev.type=macvlan
+ set network.$1_dev.ifname=$_ifname
+ set network.$1_dev.mode='vepa'
+ set network.$1.device=$1
+ set network.$1.type=macvlan
+ set network.$1.masterintf=$_ifname
+ EOF
+ _macaddr=$(uci -q get "network.$1.macaddr")
+ _setup_macaddr "$1_dev" "${_macaddr:-auto$(date +%s)}"
+}
+
+#_setup_macvlan_update() {
+# uci -q get "network.$1_dev.device" >/dev/null || return
+#
+# uci -q batch <<-EOF
+# set macvlan.$1=macvlan
+# set macvlan.$1.device=$_ifname
+# commit macvlan
+# EOF
+#}
+
+_setup_mptcp_handover_to_on() {
+ if [ "$(uci -q get network.$1.multipath)" = "handover" ]; then
+ uci -q set network.$1.multipath=on
+ fi
+ if [ "$(uci -q get openmptcprouter.$1.multipath)" = "handover" ]; then
+ uci -q set openmptcprouter.$1.multipath=on
+ fi
+}
+
+_setup_multipath_off() {
+ uci -q get "network.$1.multipath" >/dev/null && return
+ uci -q set "network.$1.multipath=off"
+}
+
+_setup_wan_interface() {
+ uci -q batch <<-EOF
+ set network.$1=interface
+ set network.$1.device=$2
+ set network.$1.proto=static
+ set network.$1.ip4table=wan
+ set network.$1.multipath=$3
+ set network.$1.defaultroute=0
+ commit network
+ add_list firewall.@zone[1].network=$1
+ commit firewall
+ EOF
+ [ -n "$4" ] && uci -q set network.$1.type=$4
+}
+
+config_load network
+#config_foreach _setup_macvlan_update interface
+config_foreach _setup_mptcp_handover_to_on interface
+
+if [ "$(uci -q show network.lan | grep multipath)" != "" ]; then
+ exit 0
+fi
+
+lanif="eth0"
+if [ "$(grep rockchip /etc/os-release)" != "" ]; then
+ lanif="eth1"
+elif [ -d /sys/class/net/lan0 -o -n "$(ip link | grep ' lan0')" ] && [ -d /sys/class/net/wan -o -n "$(ip link | grep ' wan@')" -o -n "$(ip link | grep ' wan:')" ]; then
+ lanif="wan"
+elif [ -d /sys/class/net/lan1 -o -n "$(ip link | grep ' lan1')" ] && [ -d /sys/class/net/wan -o -n "$(ip link | grep ' wan@')" -o -n "$(ip link | grep ' wan:')" ]; then
+ lanif="wan"
+elif [ -d /sys/class/net/lan ] || [ -n "$(ip link | grep ' lan')" ]; then
+ lanif="lan"
+elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ] && [ -d '/sys/class/net/eth1.5' ]; then
+ lanif="eth1.5"
+ uci -q batch <<-EOF
+ set network.@switch_vlan[0]=switch_vlan
+ set network.@switch_vlan[0].device='switch0'
+ set network.@switch_vlan[0].vlan=1
+ set network.@switch_vlan[0].vid=1
+ set network.@switch_vlan[0].ports='3 5t'
+ add network switch_vlan
+ set network.@switch_vlan[1].device='switch0'
+ set network.@switch_vlan[1].vlan=2
+ set network.@switch_vlan[1].vid=2
+ set network.@switch_vlan[1].ports='2 5t'
+ add network switch_vlan
+ set network.@switch_vlan[2].device='switch0'
+ set network.@switch_vlan[2].vlan=3
+ set network.@switch_vlan[2].vid=3
+ set network.@switch_vlan[2].ports='1 5t'
+ add network switch_vlan
+ set network.@switch_vlan[3].device='switch0'
+ set network.@switch_vlan[3].vlan=4
+ set network.@switch_vlan[3].vid=4
+ set network.@switch_vlan[3].ports='0 5t'
+ add network switch_vlan
+ set network.@switch_vlan[4].device='switch0'
+ set network.@switch_vlan[4].vlan=5
+ set network.@switch_vlan[4].vid=5
+ set network.@switch_vlan[4].ports='4 6t'
+ EOF
+elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ] && [ -d /sys/class/net/eth1 ]; then
+ lanif="eth1"
+elif [ ! -d /sys/class/net/eth1 ] && [ -d /sys/class/net/eth0 ]; then
+ lanif="eth0"
+fi
+uci -q batch <<-EOF
+delete network.lan.type
+set network.lan=interface
+set network.lan.proto=static
+set network.lan.ipaddr=192.168.100.1
+set network.lan.netmask=255.255.255.0
+set network.lan.device=${lanif}
+set network.lan.metric=2048
+set network.lan.ipv6=0
+set network.lan.delegate=0
+EOF
+
+uci -q batch <<-EOF
+delete network.none
+delete network.wan
+delete network.if6rd
+reorder network.loopback=0
+reorder network.globals=1
+reorder network.lan=2
+set network.globals.multipath=enable
+EOF
+
+# Set the ip rule for the lan with a pref of 100
+uci -q show network.lan_rule >/dev/null || \
+ uci -q batch <<-EOF
+ set network.lan_rule=rule
+ set network.lan_rule.lookup=lan
+ set network.lan_rule.priority=100
+ EOF
+
+if [ "$(uci -q get network.vpn0.proto)" = "none" ]; then
+ uci -q delete network.vpn0
+fi
+
+config_load network
+config_foreach _setup_multipath_off interface
+
+# Add the lan as a named routing table
+if ! grep -s -q "lan" /etc/iproute2/rt_tables; then
+ echo "50 lan" >> /etc/iproute2/rt_tables
+fi
+uci -q set network.lan.ip4table='lan'
+
+#uci -q set "network.lan.ip6assign=64"
+
+# Create WAN interfaces
+if [ "$(uci -q show network.wan1 | grep multipath)" = "" ] && [ -z "$(uci -q get network.wan1.multipath)" ]; then
+ if [ "$(grep rockchip /etc/os-release)" != "" ]; then
+ _setup_wan_interface wan1 eth0 master macvlan
+ _setup_wan_interface wan2 eth0 on macvlan
+ _setup_macvlan wan1
+ _setup_macvlan wan2
+ elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ]; then
+ _setup_wan_interface wan1 eth0.1 master
+ _setup_wan_interface wan2 eth0.2 on
+ _setup_wan_interface wan3 eth0.3 on
+ _setup_wan_interface wan4 eth0.4 on
+ elif [ -d /sys/class/net/wan ] || [ -n "$(ip link | grep ' wan:')" ] || [ -n "$(ip link | grep ' wan@')" ]; then
+ if [ -d /sys/class/net/lan0 -o -n "$(ip link | grep ' lan0')" ] && [ -d /sys/class/net/lan1 -o -n "$(ip link | grep ' lan1')" ]; then
+ _setup_wan_interface wan1 lan0 master
+ _setup_wan_interface wan2 lan1 on
+
+ _macaddr=$(uci -q get "network.lan0.macaddr")
+ _setup_macaddr "wan1" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ _macaddr=$(uci -q get "network.lan1.macaddr")
+ _setup_macaddr "wan2" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ if [ -d /sys/class/net/lan2 ] || [ -n "$(ip link | grep ' lan2')" ]; then
+ _setup_wan_interface wan3 lan2 on
+ _macaddr=$(uci -q get "network.lan2.macaddr")
+ _setup_macaddr "wan3" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ if [ -d /sys/class/net/lan3 ] || [ -n "$(ip link | grep ' lan3')" ]; then
+ _setup_wan_interface wan4 lan3 on
+ _macaddr=$(uci -q get "network.lan3.macaddr")
+ _setup_macaddr "wan4" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ fi
+ fi
+ elif [ -d /sys/class/net/lan1 -o -n "$(ip link | grep ' lan1')" ] && [ -d /sys/class/net/lan2 -o -n "$(ip link | grep ' lan2')" ]; then
+ _setup_wan_interface wan1 lan1 master
+ _setup_wan_interface wan2 lan2 on
+
+ _macaddr=$(uci -q get "network.lan1.macaddr")
+ _setup_macaddr "wan1" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ _macaddr=$(uci -q get "network.lan2.macaddr")
+ _setup_macaddr "wan2" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ if [ -d /sys/class/net/lan3 ] || [ -n "$(ip link | grep ' lan3')" ]; then
+ _setup_wan_interface wan3 lan3 on
+ _macaddr=$(uci -q get "network.lan3.macaddr")
+ _setup_macaddr "wan3" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ if [ -d /sys/class/net/lan4 ] || [ -n "$(ip link | grep ' lan4')" ]; then
+ _setup_wan_interface wan4 lan4 on
+ _macaddr=$(uci -q get "network.lan4.macaddr")
+ _setup_macaddr "wan4" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ fi
+ fi
+ else
+ _setup_wan_interface wan1 wan master macvlan
+ _setup_wan_interface wan2 wan on macvlan
+ _setup_macvlan wan1
+ _setup_macvlan wan2
+ fi
+ elif [ -d /sys/class/net/wan1 ] || [ -n "$(ip link | grep ' wan1')" ]; then
+ if [ -d /sys/class/net/wan2 ] || [ -n "$(ip link | grep ' wan2')" ]; then
+ _setup_wan_interface wan1 wan1 master
+ _setup_wan_interface wan2 wan2 on
+
+ _macaddr=$(uci -q get "network.wan1.macaddr")
+ _setup_macaddr "wan1" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ _macaddr=$(uci -q get "network.wan2.macaddr")
+ _setup_macaddr "wan2" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+
+ if [ -d /sys/class/net/wan3 ] || [ -n "$(ip link | grep ' wan3')" ]; then
+ _setup_wan_interface wan3 wan3 on
+ _macaddr=$(uci -q get "network.wan3.macaddr")
+ _setup_macaddr "wan3" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ if [ -d /sys/class/net/wan4 ] || [ -n "$(ip link | grep ' wan4')" ]; then
+ _setup_wan_interface wan4 wan4 on
+ _macaddr=$(uci -q get "network.wan4.macaddr")
+ _setup_macaddr "wan4" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}"
+ fi
+ fi
+ else
+ _setup_wan_interface wan1 wan1 master macvlan
+ _setup_wan_interface wan2 wan1 on macvlan
+ _setup_macvlan wan1
+ _setup_macvlan wan2
+ fi
+ elif [ -d /sys/class/net/eth1 ] || [ -n "$(ip link | grep ' eth1:')" ]; then
+ if [ -d /sys/class/net/eth2 ] || [ -n "$(ip link | grep ' eth2:')" ]; then
+ _setup_wan_interface wan1 eth1 master
+ _setup_wan_interface wan2 eth2 on
+ if [ -d /sys/class/net/eth3 ] || [ -n "$(ip link | grep ' eth3:')" ]; then
+ _setup_wan_interface wan3 eth3 on
+ fi
+ if [ -d /sys/class/net/eth4 ] || [ -n "$(ip link | grep ' eth4:')" ]; then
+ _setup_wan_interface wan4 eth4 on
+ fi
+ if [ -d /sys/class/net/eth5 ] || [ -n "$(ip link | grep ' eth5:')" ]; then
+ _setup_wan_interface wan5 eth5 on
+ fi
+ if [ -d /sys/class/net/eth6 ] || [ -n "$(ip link | grep ' eth6:')" ]; then
+ _setup_wan_interface wan6 eth6 on
+ fi
+ if [ -d /sys/class/net/eth7 ] || [ -n "$(ip link | grep ' eth7:')" ]; then
+ _setup_wan_interface wan7 eth7 on
+ fi
+ if [ -d /sys/class/net/eth8 ] || [ -n "$(ip link | grep ' eth8:')" ]; then
+ _setup_wan_interface wan8 eth8 on
+ fi
+ else
+ _setup_wan_interface wan1 eth1 master macvlan
+ _setup_wan_interface wan2 eth1 on macvlan
+ _setup_macvlan wan1
+ _setup_macvlan wan2
+ fi
+ elif [ -d /sys/class/net/eth0.1 ] && [ -d /sys/class/net/eth0.2 ]; then
+ _setup_wan_interface wan1 eth0.1 master
+ _setup_wan_interface wan2 eth0.2 on
+ else
+ _setup_wan_interface wan1 eth0 master macvlan
+ _setup_wan_interface wan2 eth0 on macvlan
+ _setup_macvlan wan1
+ _setup_macvlan wan2
+ fi
+ #uci -q batch <<-EOF
+ #add network route6
+ #set network.@route6[-1].interface='lan'
+ #set network.@route6[-1].target='::/0'
+ #EOF
+fi
+
+# Replace omrip to oip in config for old config
+sed -i 's/omrip/oip/g' /etc/config/*
+
+# Fix config from ifname to device for loopback
+uci -q delete network.loopback.ifname
+uci -q set network.loopback.device='lo'
+
+uci -q commit macvlan
+uci -q commit network
+rm -f /tmp/luci-indexcache
+exit 0
diff --git a/openmptcprouter/files/etc/uci-defaults/1970-omr-vnstat b/openmptcprouter/files/etc/uci-defaults/1970-omr-vnstat
index 2cef43a28..749b10680 100755
--- a/openmptcprouter/files/etc/uci-defaults/1970-omr-vnstat
+++ b/openmptcprouter/files/etc/uci-defaults/1970-omr-vnstat
@@ -1,24 +1,24 @@
#!/bin/sh
if [ "$(uci -q get openmptcprouter.latest_versions)" = "" ]; then
- wanintf="$(uci -q get network.wan1.ifname)"
+ wanintf="$(uci -q get network.wan1.device)"
if [ "$(uci -q get vnstat.@vnstat[-1].interface | grep $wanintf)" = "" ]; then
uci -q batch <<-EOF >/dev/null
delete vnstat.@vnstat[-1]
add vnstat vnstat
set vnstat.@vnstat[-1].interface=$wanintf
EOF
- wanintf="$(uci -q get network.wan2.ifname)"
+ wanintf="$(uci -q get network.wan2.device)"
uci -q batch <<-EOF >/dev/null
add_list vnstat.@vnstat[-1].interface=$wanintf
EOF
if [ "$(uci -q get network.wan3)" != "" ]; then
- wanintf="$(uci -q get network.wan3.ifname)"
+ wanintf="$(uci -q get network.wan3.device)"
uci -q batch <<-EOF >/dev/null
add_list vnstat.@vnstat[-1].interface=$wanintf
EOF
fi
if [ "$(uci -q get network.wan4)" != "" ]; then
- wanintf="$(uci -q get network.wan4.ifname)"
+ wanintf="$(uci -q get network.wan4.device)"
uci -q batch <<-EOF >/dev/null
add_list vnstat.@vnstat[-1].interface=$wanintf
EOF
diff --git a/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall b/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall
index 133e1d293..b31b5dbb9 100755
--- a/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall
+++ b/openmptcprouter/files/etc/uci-defaults/1980-omr-firewall
@@ -45,7 +45,7 @@ if [ "$(uci -q get firewall.zone_vpn)" = "" ]; then
uci -q batch <<-EOF >/dev/null
set firewall.zone_vpn=zone
set firewall.zone_vpn.name=vpn
- set firewall.zone_vpn.network=glorytun
+ set firewall.zone_vpn.network=omrvpn
set firewall.zone_vpn.masq=1
set firewall.zone_vpn.input=REJECT
set firewall.zone_vpn.forward=ACCEPT
@@ -98,6 +98,7 @@ if [ "$(uci -q show firewall | grep Allow-Lan-to-Wan)" = "" ]; then
set firewall.@rule[-1].name='Allow-Lan-to-Wan'
set firewall.@rule[-1].dest='wan'
set firewall.@rule[-1].src='lan'
+ set firewall.@rule[-1].proto='all'
commit firewall
EOF
fi
diff --git a/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn b/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn
index d1f5d8b86..4cb5a524c 100755
--- a/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn
+++ b/openmptcprouter/files/etc/uci-defaults/2020-omr-vpn
@@ -5,7 +5,7 @@ if [ "$(uci -q get network.omrvpn)" = "" ]; then
delete network.glorytun
delete network.omrvpn
set network.omrvpn=interface
- set network.omrvpn.ifname=tun0
+ set network.omrvpn.device=tun0
set network.omrvpn.proto=dhcp
set network.omrvpn.ip4table=vpn
set network.omrvpn.multipath=off
diff --git a/openmptcprouter/files/etc/uci-defaults/2040-omr-sqm b/openmptcprouter/files/etc/uci-defaults/2040-omr-sqm
index d8c232752..030400bb9 100755
--- a/openmptcprouter/files/etc/uci-defaults/2040-omr-sqm
+++ b/openmptcprouter/files/etc/uci-defaults/2040-omr-sqm
@@ -1,8 +1,8 @@
#!/bin/sh
if [ "$(uci -q get openmptcprouter.settings.version)" = "" ]; then
if [ "$(uci -q get sqm.wan1)" = "" ]; then
- wan1="$(uci -q get network.wan1.ifname)"
- wan2="$(uci -q get network.wan2.ifname)"
+ wan1="$(uci -q get network.wan1.device)"
+ wan2="$(uci -q get network.wan2.device)"
uci -q batch <<-EOF >/dev/null
delete sqm.eth1
set sqm.wan1=queue
@@ -34,7 +34,7 @@ if [ "$(uci -q get openmptcprouter.settings.version)" = "" ]; then
commit sqm
EOF
if [ "$(uci -q get network.wan3)" != "" ]; then
- wan3="$(uci -q get network.wan3.ifname)"
+ wan3="$(uci -q get network.wan3.device)"
uci -q batch <<-EOF >/dev/null
set sqm.wan3=queue
set sqm.wan3.qdisc="fq_codel"
@@ -53,7 +53,7 @@ if [ "$(uci -q get openmptcprouter.settings.version)" = "" ]; then
EOF
fi
if [ "$(uci -q get network.wan4)" != "" ]; then
- wan4="$(uci -q get network.wan4.ifname)"
+ wan4="$(uci -q get network.wan4.device)"
uci -q batch <<-EOF >/dev/null
set sqm.wan4=queue
set sqm.wan4.qdisc="fq_codel"