Developing lightweight computation at the DSG edge

Commit 7721fdbd authored by Roger Pueyo Centelles's avatar Roger Pueyo Centelles
Browse files

Merge branch 'qmpdoc'

parents d095ab5f f1d3c1a0
......@@ -20,9 +20,8 @@ SOURCE_WIRELESS=1
##############################
# Prepare wireless interface
#############################
# Prepare de WiFi interfaces
# Delete the wifi-iface interface in /etc/config/wireless and create an empty one
# First parameter: device
qmp_prepare_wireless_iface() {
local device=$1
qmp_uci_test wireless.$device && qmp_uci_del_raw wireless.$device
......@@ -132,6 +131,7 @@ qmp_configure_wifi_device() {
# 80211s_aplan ====> 802.11s (mesh) + access poin (LAN)
local mode="$(qmp_uci_get @wireless[$id].mode)"
local dev_disabled="0"
# Remove $device and also unneeded white spaces
local allmeshdevs="$(qmp_uci_get interfaces.mesh_devices)"
......@@ -187,7 +187,7 @@ qmp_configure_wifi_device() {
qmp_uci_set interfaces.lan_devices "$landevs"
qmp_uci_set interfaces.wan_devices "$wandevs"
echo "Interface $device is not managed by the qMp system"
return
dev_disabled="1"
;;
esac
......@@ -249,7 +249,7 @@ qmp_configure_wifi_device() {
local network="$(qmp_get_virtual_iface $device)"
local key="$(qmp_uci_get @wireless[$id].key)"
[ $(echo "$key" | wc -c) -lt 8 ] && encrypt="none" || encrypt="psk2"
local dev_id="$(echo $device | tr -d [A-z])"
dev_id=${dev_id:-$(date +%S)}
local radio="radio$dev_id"
......@@ -268,6 +268,7 @@ qmp_configure_wifi_device() {
echo "HTmode $htmode"
echo "11mode $mode11"
echo "Mrate $mrate"
echo "Disabled $dev_disabled"
echo "------------------------"
[ -z $essidap ] && essidap=$(echo ${name:0:29})"-AP"
......@@ -278,17 +279,14 @@ qmp_configure_wifi_device() {
mode="adhoc"
vap=1
}
[ $mode == "80211s_aplan" ] && {
mode="80211s"
vap=1
}
device_template="$TEMPLATE_BASE/device.$driver-$mode11"
iface_template="$TEMPLATE_BASE/iface.$mode"
vap_template="$TEMPLATE_BASE/iface.ap"
[ ! -f "$device_template" ] || [ ! -f "$iface_template" ] && qmp_error "Template $template not found"
[ ! -f "$device_template" ] && qmp_error "Device template $device_template not found"
cat $device_template | grep -v ^# | grep -v "^list " | sed \
-e s/"#QMP_RADIO"/"$radio"/ \
......@@ -299,7 +297,13 @@ qmp_configure_wifi_device() {
-e s/"#QMP_MRATE"/"$mrate"/ \
-e s/"#QMP_HTMODE"/"$htmode"/ \
-e s/"#QMP_TXPOWER"/"$txpower"/ > $TMP/qmp_wifi_device
echo "wireless.$radio.disabled="$dev_disabled >> $TMP/qmp_wifi_device
[ $mode != "none" ] && {
echo $device
iface_template="$TEMPLATE_BASE/iface.$mode"
[ ! -f "$iface_template" ] && qmp_error "Interface template $iface_template not found"
echo $device
qmp_prepare_wireless_iface $device
echo "Mode is $mode"
......@@ -318,8 +322,11 @@ qmp_configure_wifi_device() {
-e s/"#QMP_KEY"/"$key"/ \
-e s/"#QMP_MODE"/"$mode"/ > $TMP/qmp_wifi_iface
}
# If virtual AP interface has to be configured
vap_template="$TEMPLATE_BASE/iface.ap"
[ ! -f "$vap_template" ] && qmp_error "Virtual AP template $vap_template not found"
[ "$vap" == "1" ] && {
qmp_prepare_wireless_iface ${device}ap
cat $vap_template | grep -v ^# | sed \
......@@ -332,19 +339,21 @@ qmp_configure_wifi_device() {
-e s/"#QMP_KEY"/"$key"/ \
-e s/"#QMP_MODE"/"ap"/ >> $TMP/qmp_wifi_iface
}
echo "AAAA 16"
qmp_uci_import $TMP/qmp_wifi_iface
echo "AAAA 16b"
qmp_uci_import $TMP/qmp_wifi_device
echo "AAAA 17"
# List arguments (needed for HT capab)
cat $device_template | grep -v ^# | grep "^list " | sed s/"^list "//g | sed \
-e s/"#QMP_RADIO"/"$radio"/ | while read l; do
qmp_uci_add_list_raw $l
done
echo "AAAA 18"
uci reorder wireless.$radio=0
#uci reorder wireless.@wifi-iface[$index]=16
uci commit wireless
echo "AAAA 18"
}
#############################
......@@ -550,12 +559,11 @@ qmp_reset_wifi() {
#Generating default wifi configuration
country="$(uci get qmp.wireless.country 2>/dev/null)"
country="${country:-US}"
mv /etc/config/wireless /tmp/wireless.old
wifi config
sed -i s/"disabled '1'"/"country $country"/g /etc/config/wireless
wifi
wifi
sleep 5
}
......
......@@ -11,6 +11,7 @@ function print_help()
print(" channels <dev> : supported channels and supported HT40 type (+/-) ")
print(" txpower <dev> : supported transmission powers")
print(" devices [wifi|eth] : print all physical network devices")
print(" radios : print all wireless network physical interfaces")
print(" ipv4 : print all ipv4 from this computer (excluding localhost)")
print(" hostname : print device hostname")
print(" bwtest <ipv6> : perform a bandwidth test")
......@@ -46,19 +47,30 @@ end
function print_devices()
local _,v,devs
if op1 == nil then
devs = qmpinfo.get_devices().all
elseif op1 == "wifi" then
if op1 == "wifi" then
devs = qmpinfo.get_devices().wifi
else
elseif op1 == "eth" then
devs = qmpinfo.get_devices().eth
else
devs = qmpinfo.get_devices().all
end
for _,v in ipairs(devs) do
print(v)
end
end
function print_radios()
local _,v,devs
devs = qmpinfo.get_radios()
for _,v in ipairs(devs) do
print(v)
end
end
function print_txpower()
local data = qmpinfo.get_txpower(op1)
for _,v in ipairs(data) do
......@@ -144,6 +156,8 @@ elseif question == "txpower" then
print_txpower()
elseif question == "devices" then
print_devices()
elseif question == "radios" then
print_radios()
elseif question == "ipv4" then
print_ipv4()
elseif question == "hostname" then
......@@ -161,4 +175,3 @@ elseif question == "version" then
else
print_help()
end
......@@ -46,33 +46,34 @@ function qmpinfo.get_qmp_devices()
return devs
end
-- returns all the physical devices as a table
-- in table.wifi only the wifi ones
-- in table.eth only the non-wifi ones
function qmpinfo.get_devices()
local d
local phydevs = {}
phydevs.wifi = {}
function qmpinfo.get_devices()
local d
local phydevs = {}
phydevs.wifi = {}
phydevs.all = {}
phydevs.eth = {}
local ignored = util.split( uci:get("qmp","interfaces","ignore_devices") or ""," ")
local sysnet = "/sys/class/net/"
local qmp_devs = qmpinfo.get_qmp_devices()
local sysnet = "/sys/class/net/"
local qmp_devs = qmpinfo.get_qmp_devices()
for d in nixio.fs.dir(sysnet) do
local is_qmp_dev = isInTable(qmp_devs,d)
local is_qmp_dev = isInTable(qmp_devs,d)
if is_qmp_dev or nixio.fs.stat(sysnet..d..'/device',"type") ~= nil then
if is_qmp_dev or (string.find(d,"%.") == nil and string.find(d,"ap") == nil) then
local ignore = isInTable(ignored,d)
if not ignore then
if not ignore then
if nixio.fs.stat(sysnet..d..'/phy80211',"type") ~= nil then
table.insert(phydevs.wifi,d)
else
table.insert(phydevs.wifi,d)
else
local toadd = true
for e in nixio.fs.dir(sysnet) do
local toadd = true
for e in nixio.fs.dir(sysnet) do
-- if device e is a switched port of device d (e.g. if e=eth0.1 and d=eth0)
-- but not if e=eth0_12 and d=eth0
if toadd == true and string.match(e, d .. '%.') and nixio.fs.stat(sysnet..d..'/upper_'..e,"type") ~= nil then
......@@ -91,7 +92,31 @@ function qmpinfo.get_devices()
end
end
return phydevs
table.sort(phydevs)
return phydevs
end
-- Get a sorted array with the wireless (IEEE 802.11) radio devices (e.g. radio0, radio1, radio2)
function qmpinfo.get_radios()
local rdevices = {}
local conn = ubus.connect()
if conn then
local status = conn:call("network.wireless", "status", {})
-- Check all the devices returned by the Ubus call
for k, v in pairs(status) do
table.insert(rdevices, k)
end
conn:close()
end
table.sort(rdevices)
return rdevices
end
-- deprecated
......@@ -338,4 +363,3 @@ function qmpinfo.get_key()
end
return qmpinfo
--[[
Copyright (C) 2011 Fundacio Privada per a la Xarxa Oberta, Lliure i Neutral guifi.net
qMp - Quick Mesh Project - https://www.qmp.cat
Copyright © 2011-2017 Fundació Privada per a la Xarxa Oberta, Lliure i Neutral, guifi.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
module("luci.controller.qmp", package.seeall)
......@@ -34,21 +31,23 @@ function index()
overview.sysauth = "root"
overview.sysauth_authenticator = "htmlauth"
-- Rest of entries
-- Menu entries
entry({"qmp","status"}, template("admin_status/index"), "Status", 2).dependent=false
entry({"qmp","configuration"}, cbi("qmp/easy_setup"), "Device configuration", 4).dependent=false
entry({"qmp","configuration","easy_setup"}, cbi("qmp/easy_setup"), "qMp easy setup", 1).dependent=false
entry({"qmp","configuration","basic"}, cbi("qmp/basic"), "Basic settings", 2).dependent=false
entry({"qmp","configuration","network"}, cbi("qmp/network"), "Network settings", 3).dependent=false
entry({"qmp","configuration","network","advanced"}, cbi("qmp/network_adv"), "Advanced network settings", 1).dependent=false
entry({"qmp","configuration","wifi"}, cbi("qmp/wireless"), "Wireless settings", 4).dependent=false
entry({"qmp","configuration","services"}, cbi("qmp/services"), "qMp services", 5).dependent=false
entry({"qmp","configuration","gateways"}, cbi("qmp/gateways"), "qMp gateways", 6).dependent=false
entry({"qmp","configuration"}, cbi("qmp/easy_setup"), "Device configuration", 4).dependent=false
entry({"qmp","configuration","easy_setup"}, cbi("qmp/easy_setup"), "qMp easy setup", 10).dependent=false
entry({"qmp","configuration","node"}, cbi("qmp/node"), "Node settings", 20).dependent=false
entry({"qmp","configuration","network"}, cbi("qmp/network_basic"), "Network settings", 30).dependent=false
entry({"qmp","configuration","network","basic"}, cbi("qmp/network_basic"), "Basic settings", 31).dependent=false
entry({"qmp","configuration","network","wired"}, cbi("qmp/network_wired"), "Wired interfaces", 32).dependent=false
entry({"qmp","configuration","network","wireless"}, cbi("qmp/network_wireless"), "Wireless interfaces", 33).dependent=false
entry({"qmp","configuration","network","advanced"}, cbi("qmp/network_adv"), "Advanced settings", 34).dependent=false
entry({"qmp","configuration","services"}, cbi("qmp/services"), "qMp services", 40).dependent=false
entry({"qmp","configuration","gateways"}, cbi("qmp/gateways"), "qMp gateways", 50).dependent=false
entry({"qmp","tools"}, call("action_tools"), "Tools", 5).dependent=false
entry({"qmp","tools","tools"}, call("action_tools"), "Network testing", 1).dependent=false
if nixio.fs.stat("/usr/lib/lua/luci/model/cbi/qmp/mdns.lua","type") ~= nil then
if nixio.fs.stat("/usr/lib/lua/luci/model/cbi/qmp/mdns.lua","type") ~= nil then
entry({"qmp","tools","mDNS"}, cbi("qmp/mdns"), "DNS mesh", 1).dependent=false
end
-- entry({"qmp","tools","splash"}, call("action_splash"), "Splash", 2).dependent=false
......@@ -63,7 +62,7 @@ function action_status()
local ipv4 = qmp.get_ipv4()
local hostname = qmp.get_hostname()
local uname = qmp.get_uname()
local version = qmp.get_version()
local version = qmp.get_version()
luci.template.render("qmp/overview",{ipv4=ipv4,hostname=hostname,uname=uname,version=version})
end
......@@ -83,4 +82,3 @@ end
function action_map()
luci.template.render("qmp/b6m")
end
--[[
Copyright (C) 2011 Fundacio Privada per a la Xarxa Oberta, Lliure i Neutral guifi.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
--]]
require("luci.sys")
local http = require "luci.http"
local uciout = uci.cursor()
m = Map("qmp", "Basic qMp device settings")
local networkmode
if uciout:get("qmp","roaming","ignore") == "1" then
networkmode="community"
else
networkmode="roaming"
end
device_section = m:section(NamedSection, "node", "qmp", translate("Device identity"), translate("Use this page to define basic qMp settings, like the device\'s name, etc."))
device_section.addremove = False
if networkmode == "community" then
community_name = device_section:option(Value, "community_name", translate ("Community Network name"), translate("Select a predefined Community Network or type your own name."))
community_name.datatype="string"
community_name:value("Bogotá Mesh","Bogotá Mesh")
community_name:value("DigitalMerthyr","Digital Merthyr")
community_name:value("Guifi.net","Guifi.net")
community_name:value("NYCMesh","NYC Mesh")
guifimesh_name = device_section:option(Value, "mesh_name", translate ("Mesh Network name"), translate("Select a predefined Mesh Network or type your own name."))
guifimesh_name:depends("community_name","Guifi.net")
guifimesh_name.datatype="string"
guifimesh_name:value("GuifiBaix", "Baix Llobregat (GB)")
guifimesh_name:value("Bellvitge", "Bellvitge")
guifimesh_name:value("GraciaSenseFils", "Gràcia Sense Fils (GSF)")
guifimesh_name:value("PoblenouSenseFils", "Poblenou Sense Fils (P9SF)")
guifimesh_name:value("Quesa", "Quesa (QUESA)")
guifimesh_name:value("Raval", "Raval (GuifiBaix)")
guifimesh_name:value("GuifiSants", "Sants-Les Corts-UPC (GS)")
guifimesh_name:value("SantAndreu", "Sant Andreu (SAND)")
guifimesh_name:value("Vallcarca", "Vallcarca (VKK)")
end
device_name = device_section:option(Value,"device_name", translate("Device name"), translate("The name for this device (use alphanumeric characters, without spaces)."))
device_name.default = "qMp"
device_name.datatype = "hostname"
device_name.optional = false
device_id = device_section:option(Value,"device_id", translate("Device id"), translate("The id of this device in the mesh network (use alphanumeric characters, without spaces)."))
device_id.datatype = "string"
device_id.optional = true
primary_device = device_section:option(Value,"primary_device", translate("Primary network device"), translate("The name of the node's primary network device. The last four digits of this device's MAC address will be appended to the node name."))
primary_device.default = "eth0"
primary_device.datatype = "network"
location_section = m:section(NamedSection, "node", "qmp", translate("Device location"))
location_section.addremove = False
geopos_lat = location_section:option(Value,"latitude", translate("Latitude"), translate("Latitude geoposition to use in the maps (optional)."))
geopos_lon = location_section:option(Value,"longitude", translate("Longitude"), translate("Longitude geoposition to use in the maps (optional)."))
geopos_elv = location_section:option(Value,"elevation", translate("Elevation"), translate("Elevation of the node relative to the ground level (optional)."))
contact_section = m:section(NamedSection, "node", "qmp", translate("Contact information"))
contact_section.addremove = False
contact = contact_section:option(Value,"contact", translate("Contact e-mail"), translate("An e-mail to contact you if needed (optional)."))
function m.on_commit(self,map)
http.redirect("/luci-static/resources/qmp/wait_short.html")
luci.sys.exec('/etc/qmp/qmp_control.sh configure_system > /tmp/qmp_control_system.log &')
end
return m
--[[
Copyright (C) 2011 Fundacio Privada per a la Xarxa Oberta, Lliure i Neutral guifi.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
--]]
package.path = package.path .. ";/etc/qmp/?.lua"
qmpinfo = require "qmpinfo"
require("luci.sys")
local http = require "luci.http"
m = Map("qmp", "qMp network settings")
eth_section = m:section(NamedSection, "interfaces", "qmp", translate("Network mode"), translate("Select the working mode of the wired network interfaces: <br/> · LAN mode is used to provide end-users connectivity and a DHCP will be enabled to assign IP addresses to the devices connecting.<br/> · WAN mode is used on interfaces connected to an Internet up-link or any other gateway connection.<br/> <br/>LAN and WAN modes are mutually exclusive. <strong>Do not set an interface in both LAN and WAN modes.</strong>"))
eth_section.addremove = False
mesh_section = m:section(NamedSection, "interfaces", "qmp", translate("Mesh interfaces"), translate("Select the devices that will be used in the mesh network. It is recommended to select them all."))
eth_section.addremove = False
special_section = m:section(NamedSection, "interfaces", "qmp", translate("Special settings"), translate("Use this section to disable VLAN tagging in certain interfaces or to exclude them from qMp."))
mesh_section.addremove = False
-- Getting the physical (real) interfaces
net_int = qmpinfo.get_devices().all
-- Option: lan_devices
lan = eth_section:option(MultiValue, "lan_devices", translate("LAN mode"),translate("Interfaces used to provide end-user connectivity (DHCP server)"))
local i,l
for i,l in ipairs(net_int) do
lan:value(l,l)
end
-- Option wan_device
wan = eth_section:option(MultiValue, "wan_devices", "WAN mode","Interfaces connected to an Internet up-link or any other gateway (DHCP client)")
for i,l in ipairs(net_int) do
wan:value(l,l)
end
-- Option mesh_devices
mesh = mesh_section:option(MultiValue, "mesh_devices", "MESH devices","Devices used for meshing (it is recommended to check them all)")
for i,l in ipairs(net_int) do
mesh:value(l,l)
end
no_vlan = special_section:option(Value, "no_vlan_devices", translate("VLAN-untagged devices"),translate("Devices that will not be used with VLAN tagging (it is recommended to leave it blank)"))
ignore_devs = special_section:option(Value, "ignore_devices", translate("Excluded devices"),translate("Devices that will not be used by qMp"))
function m.on_commit(self,map)
http.redirect("/luci-static/resources/qmp/wait_long.html")
luci.sys.call('qmpcontrol configure_network > /tmp/qmp_control_network.log &')
end
return m
--[[
Copyright (C) 2011 Fundacio Privada per a la Xarxa Oberta, Lliure i Neutral guifi.net
qMp - Quick Mesh Project - https://www.qmp.cat
Copyright © 2011-2017 Fundació Privada per a la Xarxa Oberta, Lliure i Neutral, guifi.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
require("luci.sys")
local http = require "luci.http"
m = Map("qmp", "qMp advanced network settings")
m = Map("qmp", "qMp advanced network settings", translate("This page allows to configure the advanced network settings of a qMp device, like IPv4 and IPv6 addresses, prefixes, DHCP behaviour, etc.") .. "<br/> <br/>" .. translate("You can check the on-line documentation at <a href=\"https://www.qmp.cat/Web_interface\">https://www.qmp.cat/Web_interface</a> for more information about the different options."))
ethernet_interfaces = { 'eth', 'ath', 'wlan' }
wireless_interfaces = { 'ath', 'wlan' }
......@@ -35,12 +32,13 @@ eth_section:option(Value, "dns", "DNS nameservers",translate("Define the nameser
-- Option: lan addresses
eth_section:option(Value, "lan_address", "LAN IP address",translate("IPv4 address for the LAN interfaces."))
-- Option: lan addresses
eth_section:option(Value, "lan_netmask", "LAN netmask",translate("IPv4 netmask for the LAN interfaces."))
-- Option: lan netmask
lannetmask=eth_section:option(Value, "lan_netmask", "LAN netmask",translate("IPv4 netmask for the LAN interfaces."))
lannetmask.datatype="ip4addr"
-- Option: publish lan
--eth_section:option(Flag, "publish_lan", "Publish LAN", "Publish LAN network through the mesh")
-- Option: disable dhcp lan
eth_section:option(Flag, "disable_lan_dhcp", "Disable DHCP server in LAN",
translate("Disable DHCP server in LAN network (not recommended)."))
......@@ -84,7 +82,17 @@ overlapping_section:option(Value, "dhcp_offset", "DHCP offset",
translate("Offset to calculate the first IP to give via DHCP"))
-- Option: Leassetime
overlapping_section:option(Value, "qmp_leasetime", "DHCP leas etime",translate("Lease time for the DHCP server"))
overlapping_section:option(Value, "qmp_leasetime", "DHCP lease time",translate("Lease time for the DHCP server"))
----------------------
-- Special settings
----------------------
special_section = m:section(NamedSection, "interfaces", "qmp", translate("Special settings"), translate("Use this section to disable VLAN tagging in certain interfaces or to exclude them from qMp."))
special_section.addremove = False