Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • autinerd/experimental-openwrt-24.10
  • experimental
  • feature/addMikrotikwAP
  • master
  • nrb/airmax-test
  • nrb/ar9344-reset-sequence
  • nrb/ex400-remove-wps
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2022.1.1-ffs
  • v2022.1.3-ffs
  • v2022.1.4-ffs
  • v2023.1-ffs
  • v2023.2-ffs
  • v2023.2.2-ffs
  • v2023.2.3-ffs
  • v2023.2.4-ffs
  • v2023.2.5-ffs
  • experimental-2022-09-24
  • experimental-2022-09-24-base
  • experimental-2023-03-11
  • experimental-2023-03-11-base
  • experimental-2023-03-12
  • experimental-2023-03-12-base
  • experimental-2023-03-16
  • experimental-2023-03-16-base
  • experimental-2023-03-20
  • experimental-2023-03-20-base
  • experimental-2023-03-23
  • experimental-2023-03-23-base
  • experimental-2023-03-25
  • experimental-2023-03-25-base
  • experimental-2023-03-26
  • experimental-2023-03-26-base
  • experimental-2023-03-30
  • experimental-2023-03-30-base
  • experimental-2023-03-31
  • experimental-2023-03-31-base
  • experimental-2023-04-01
  • experimental-2023-04-01-base
  • experimental-2023-04-08
  • experimental-2023-04-08-base
  • experimental-2023-04-10
  • experimental-2023-04-10-base
  • experimental-2023-04-13
  • experimental-2023-04-13-base
  • experimental-2023-04-15
  • experimental-2023-04-15-base
  • experimental-2023-04-16
  • experimental-2023-04-16-base
  • experimental-2023-04-18
  • experimental-2023-04-18-base
  • experimental-2023-04-20
  • experimental-2023-04-20-base
  • experimental-2023-04-26
  • experimental-2023-04-26-base
  • experimental-2023-04-28
  • experimental-2023-04-28-base
  • experimental-2023-04-30
  • experimental-2023-04-30-base
  • experimental-2023-05-02
  • experimental-2023-05-02-base
  • experimental-2023-05-03
  • experimental-2023-05-03-base
  • experimental-2023-05-12
  • experimental-2023-05-12-base
  • experimental-2023-05-21
  • experimental-2023-05-21-base
  • experimental-2023-05-25
  • experimental-2023-05-25-base
  • experimental-2023-07-02
  • experimental-2023-07-02-base
  • experimental-2023-07-04
  • experimental-2023-07-04-base
  • experimental-2023-07-12
  • experimental-2023-07-12-base
  • experimental-2023-07-16
  • experimental-2023-07-16-base
  • experimental-2023-08-04
  • experimental-2023-08-04-base
  • experimental-2023-08-10
  • experimental-2023-08-10-base
  • experimental-2023-09-08
  • experimental-2023-09-08-base
  • experimental-2023-09-09
  • experimental-2023-09-09-base
  • experimental-2023-09-10
  • experimental-2023-09-10-base
  • experimental-2023-09-11
  • experimental-2023-09-11-base
  • experimental-2023-09-12
  • experimental-2023-09-12-base
  • experimental-2023-09-13
  • experimental-2023-09-13-base
  • experimental-2023-09-15
  • experimental-2023-09-15-base
  • experimental-2023-09-16
  • experimental-2023-09-16-base
  • experimental-2023-09-18
  • experimental-2023-09-18-base
  • experimental-2023-09-20
  • experimental-2023-09-20-base
  • experimental-2023-09-27
  • experimental-2023-09-27-base
  • experimental-2023-09-28
  • experimental-2023-09-28-base
  • experimental-2023-09-29
  • experimental-2023-09-29-base
  • experimental-2023-10-02
  • experimental-2023-10-02-base
  • experimental-2023-10-13
  • experimental-2023-10-13-base
  • experimental-2023-10-14
  • experimental-2023-10-14-base
  • experimental-2023-10-16
  • experimental-2023-10-16-base
  • experimental-2023-10-23
  • experimental-2023-10-23-base
137 results

Target

Select target project
  • firmware/gluon
  • 0x4A6F/gluon
  • patrick/gluon
3 results
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • 2014.3.x
  • 2014.4.x
  • babel
  • experimental
  • hoodselector
  • master
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • radv-filterd
  • v2015.1.x
  • v2016.1.x
  • v2016.2.4-batmanbug
  • v2016.2.x
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2018.2.x
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2020.2.x
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2014.1
  • v2014.2
  • v2014.3
  • v2014.3.1
  • v2014.4
  • v2015.1
  • v2015.1.1
  • v2015.1.2
  • v2016.1
  • v2016.1.1
  • v2016.1.2
  • v2016.1.3
  • v2016.1.4
  • v2016.1.5
  • v2016.1.6
  • v2016.2
  • v2016.2.1
  • v2016.2.2
  • v2016.2.3
  • v2016.2.4
  • v2016.2.5
  • v2016.2.6
  • v2016.2.7
  • v2017.1
  • v2017.1.1
  • v2017.1.2
  • v2017.1.3
  • v2017.1.4
  • v2017.1.5
  • v2017.1.6
  • v2017.1.7
  • v2017.1.8
  • v2018.1
  • v2018.1.1
  • v2018.1.2
  • v2018.1.3
  • v2018.1.4
  • v2018.2
  • v2018.2-ffs0.1
  • v2018.2.1
  • v2018.2.1-ffs0.1
  • v2018.2.2-ffs0.1
  • v2018.2.3-ffs0.1
  • v2019.1-ffs0.1
  • v2019.1.1-ffs0.1
  • v2019.1.2-ffs0.1
  • v2020.1-ffs0.1
  • v2020.1.1-ffs0.1
  • v2020.1.3-ffs0.1
  • v2020.2
  • v2020.2-ffs0.1
  • v2020.2.1-ffs0.1
  • v2020.2.2-ffs0.1
  • v2020.2.3-ffs0.1
  • v2020.2.3-ffs0.2
  • v2020.2.3-ffs0.3
  • v2020.2.x-ffs0.1
  • v2021.1-ffs0.1
  • v2021.1.1-ffs0.1
  • v2021.1.1-ffs0.2
  • v2021.1.1-ffs0.3
  • v2021.1.1-ffs0.4
  • v2021.1.2-ffs0.1
  • v2021.1.2-ffs0.2
98 results
Show changes
Showing
with 836 additions and 290 deletions
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local platform = require 'gluon.platform'
-- This is a workaround to result in a configuration where all ports
-- on the DSA switch are connected to the same CPU interface.
--
-- See Gluon issue #3479 for details.
-- https://github.com/freifunk-gluon/gluon/issues/3479
if not platform.match('ipq806x', 'generic', {
'netgear,r7800',
'tplink,c2600',
}) then
return
end
local ports = {
'lan1',
'lan2',
'lan3',
'lan4',
'wan',
}
local cpu_conduit = 'eth0'
for _, port in ipairs(ports) do
local section_name = 'port_' .. port
uci:section('network', 'device', section_name, {
name = port,
conduit = cpu_conduit,
})
end
uci:save('network')
#!/usr/bin/lua
local site = require 'gluon.site'
local uci = require('simple-uci').cursor()
local util = require 'gluon.util'
local mesh_interfaces = util.get_role_interfaces(uci, 'mesh')
local uplink_interfaces = util.get_role_interfaces(uci, 'uplink')
local mesh_interfaces_uplink = {}
local mesh_interfaces_other = {}
for _, iface in ipairs(mesh_interfaces) do
if util.contains(uplink_interfaces, iface) then
table.insert(mesh_interfaces_uplink, iface)
else
table.insert(mesh_interfaces_other, iface)
end
end
if #mesh_interfaces_uplink > 0 then
uci:section('network', 'interface', 'mesh_uplink', {
ifname = 'br-wan',
proto = 'gluon_wired',
index = 0,
vxlan = site.mesh.vxlan(true),
})
end
if #mesh_interfaces_other > 0 then
local iftype, ifname
if #mesh_interfaces_other == 1 then
ifname = mesh_interfaces_other[1]
else
iftype = 'bridge'
ifname = mesh_interfaces_other
for _, iface in ipairs(ifname) do
uci:section('network', 'device', nil, {
name = iface,
isolate = true,
})
end
end
uci:section('network', 'interface', 'mesh_other', {
ifname = ifname,
type = iftype,
igmp_snooping = false,
proto = 'gluon_wired',
index = 4,
vxlan = site.mesh.vxlan(true),
})
end
uci:save('network')
#!/usr/bin/lua
local site = require 'gluon.site'
local uci = require('simple-uci').cursor()
uci:section('network', 'interface', 'mesh_wan', {
ifname = 'br-wan',
proto = 'gluon_wired',
index = 0,
})
local enable = site.mesh_on_wan(false)
local old_auto = uci:get('network', 'mesh_wan', 'auto')
local old_disabled = uci:get('network', 'mesh_wan', 'disabled')
if old_auto ~= nil or old_disabled ~= nil then
enable = old_auto ~= '0' and old_disabled ~= '1'
end
uci:set('network', 'mesh_wan', 'disabled', not enable)
if uci:get('network', 'mesh_wan', 'transitive') == nil then
uci:set('network', 'mesh_wan', 'transitive', true)
end
uci:delete('network', 'mesh_wan', 'auto')
uci:delete('network', 'mesh_wan', 'fixed_mtu')
uci:delete('network', 'mesh_wan', 'legacy')
uci:save('network')
#!/usr/bin/lua
local site = require 'gluon.site'
local util = require 'gluon.util'
local sysconfig = require 'gluon.sysconfig'
local uci = require('simple-uci').cursor()
if not sysconfig.lan_ifname then
os.exit(0)
end
uci:section('network', 'interface', 'mesh_lan', {
ifname = sysconfig.lan_ifname,
igmp_snooping = false,
proto = 'gluon_wired',
index = 4,
})
if sysconfig.lan_ifname:match(' ') then
uci:set('network', 'mesh_lan', 'type', 'bridge')
else
uci:delete('network', 'mesh_lan', 'type')
end
local enable = site.mesh_on_lan(false)
local old_auto = uci:get('network', 'mesh_lan', 'auto')
local old_disabled = uci:get('network', 'mesh_lan', 'disabled')
if old_auto ~= nil or old_disabled ~= nil then
enable = old_auto ~= '0' and old_disabled ~= '1'
end
if enable then
local interfaces = uci:get_list('network', 'client', 'ifname')
if interfaces then
for lanif in sysconfig.lan_ifname:gmatch('%S+') do
if util.contains(interfaces, lanif) then
enable = false
break
end
end
end
end
uci:set('network', 'mesh_lan', 'disabled', not enable)
if uci:get('network', 'mesh_lan', 'transitive') == nil then
uci:set('network', 'mesh_lan', 'transitive', true)
end
uci:delete('network', 'mesh_lan', 'auto')
uci:delete('network', 'mesh_lan', 'fixed_mtu')
uci:delete('network', 'mesh_lan', 'legacy')
uci:save('network')
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local platform = require 'gluon.platform'
if not platform.is_cellular_device() then
return
end
local function set_or_delete(package, section, option, val)
if val ~= nil and string.len(val) ~= 0 then
uci:set(package, section, option, val)
else
uci:delete(package, section, option)
end
end
local function setup_ncm_qmi(devpath, control_type, delay)
local pdptype = uci:get('gluon', 'cellular', 'pdptype')
local pincode = uci:get('gluon', 'cellular', 'pin')
local username = uci:get('gluon', 'cellular', 'username')
local password = uci:get('gluon', 'cellular', 'password')
local auth = uci:get('gluon', 'cellular', 'auth')
uci:section('network', 'interface', 'cellular', {
proto = control_type,
device = devpath,
disabled = not uci:get_bool('gluon', 'cellular', 'enabled'),
pdptype = pdptype,
peerdns = false,
apn = uci:get('gluon', 'cellular', 'apn'),
})
if pdptype ~= 'IP' then
uci:set('network', 'cellular', 'ipv6', 'auto')
else
uci:delete('network', 'cellular', 'ipv6')
end
set_or_delete('network', 'cellular', 'pincode', pincode)
set_or_delete('network', 'cellular', 'username', username)
set_or_delete('network', 'cellular', 'password', password)
set_or_delete('network', 'cellular', 'auth', auth)
set_or_delete('network', 'cellular', 'delay', delay)
end
if platform.match('ath79', 'nand', {
'glinet,gl-e750',
'glinet,gl-xe300',
}) then
setup_ncm_qmi('/dev/cdc-wdm0', 'qmi', 15)
elseif platform.match('ath79', 'nand', {
'zte,mf281',
}) then
setup_ncm_qmi('/dev/ttyACM0', 'ncm', 15)
elseif platform.match('ipq40xx', 'generic', {
'glinet,gl-ap1300',
'zte,mf289f',
}) then
setup_ncm_qmi('/dev/cdc-wdm0', 'qmi', 15)
elseif platform.match('ramips', 'mt7621', {
'wavlink,ws-wn572hp3-4g',
}) then
setup_ncm_qmi('/dev/ttyUSB2', 'ncm', 15)
elseif platform.match('ramips', 'mt76x8', {
'tplink,tl-mr6400-v5',
}) then
setup_ncm_qmi('/dev/cdc-wdm0', 'qmi', 15)
end
uci:save('network')
#!/usr/bin/lua #!/usr/bin/lua
local uci = require('simple-uci').cursor() local uci = require('simple-uci').cursor()
local platform = require 'gluon.platform'
local defaults = uci:get_first('firewall', 'defaults') local defaults = uci:get_first('firewall', 'defaults')
...@@ -16,9 +17,19 @@ local function reject_input_on_wan(zone) ...@@ -16,9 +17,19 @@ local function reject_input_on_wan(zone)
return true return true
end end
local function add_cellular_wan(zone)
if zone.name == 'wan' then
uci:set('firewall', zone['.name'], 'network', {'wan', 'wan6', 'cellular_4', 'cellular_6'})
end
end
uci:foreach('firewall', 'zone', reject_input_on_wan) uci:foreach('firewall', 'zone', reject_input_on_wan)
for _, zone in ipairs({'mesh', 'local_client', 'wired_mesh'}) do if platform.is_cellular_device() then
uci:foreach('firewall', 'zone', add_cellular_wan)
end
for _, zone in ipairs({'mesh', 'loc_client', 'wired_mesh'}) do
-- Other packages assign interfaces to these zones -- Other packages assign interfaces to these zones
uci:section('firewall', 'zone', zone, { uci:section('firewall', 'zone', zone, {
name = zone, name = zone,
...@@ -52,13 +63,10 @@ for _, zone in ipairs({'mesh', 'local_client', 'wired_mesh'}) do ...@@ -52,13 +63,10 @@ for _, zone in ipairs({'mesh', 'local_client', 'wired_mesh'}) do
family = 'ipv6', family = 'ipv6',
target = 'ACCEPT', target = 'ACCEPT',
}) })
-- Can be removed soon: was never in a release
uci:delete('firewall', zone .. '_ICMPv6_out')
end end
uci:section('firewall', 'rule', 'local_client_ICMPv4_in', { uci:section('firewall', 'rule', 'loc_client_ICMPv4_in', {
src = 'local_client', src = 'loc_client',
proto = 'icmp', proto = 'icmp',
icmp_type = { icmp_type = {
'echo-request', 'echo-request',
...@@ -67,9 +75,8 @@ uci:section('firewall', 'rule', 'local_client_ICMPv4_in', { ...@@ -67,9 +75,8 @@ uci:section('firewall', 'rule', 'local_client_ICMPv4_in', {
target = 'ACCEPT', target = 'ACCEPT',
}) })
-- allow inbound SSH from anywhere -- allow inbound SSH from anywhere
for _, zone in ipairs({ 'wan', 'local_client', 'mesh' }) do for _, zone in ipairs({ 'wan', 'loc_client', 'mesh' }) do
uci:section('firewall', 'rule', zone .. '_ssh', { uci:section('firewall', 'rule', zone .. '_ssh', {
name = zone .. '_ssh', name = zone .. '_ssh',
src = zone, src = zone,
...@@ -80,9 +87,18 @@ for _, zone in ipairs({ 'wan', 'local_client', 'mesh' }) do ...@@ -80,9 +87,18 @@ for _, zone in ipairs({ 'wan', 'local_client', 'mesh' }) do
end end
-- We can't put mesh_wan into this zone, as mesh_wan is the same local wired_mesh_ifaces = {}
uci:foreach('network', 'interface',
function(iface)
-- Select all interfaces with proto gluon_wired except for
-- mesh_uplink into this zone, as mesh_uplink is the same
-- interface as wan, which has its own zone -- interface as wan, which has its own zone
uci:set('firewall', 'wired_mesh', 'network', {'mesh_lan'}) if iface['proto'] == 'gluon_wired' and iface['.name'] ~= 'mesh_uplink' then
table.insert(wired_mesh_ifaces, iface['.name'])
end
end
)
uci:set('firewall', 'wired_mesh', 'network', wired_mesh_ifaces)
-- VXLAN for wired meshing -- VXLAN for wired meshing
for _, zone in ipairs({'wired_mesh', 'wan'}) do for _, zone in ipairs({'wired_mesh', 'wan'}) do
......
...@@ -14,7 +14,7 @@ local util = require 'gluon.util' ...@@ -14,7 +14,7 @@ local util = require 'gluon.util'
local subst = {} local subst = {}
local f = io.popen('. /etc/os-release; echo "$ID"; echo "$VERSION_ID"; echo "$LEDE_BOARD"; echo "$LEDE_ARCH"') local f = io.popen('. /etc/os-release; echo "$ID"; echo "$VERSION_ID"; echo "$OPENWRT_BOARD"; echo "$OPENWRT_ARCH"')
subst['%%d'] = f:read() subst['%%d'] = f:read()
subst['%%v'] = f:read():gsub('-snapshot', '') subst['%%v'] = f:read():gsub('-snapshot', '')
subst['%%S'] = f:read() subst['%%S'] = f:read()
......
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local function migrate_iface(iface)
if iface.proto ~= 'batadv' or iface.mesh ~= 'bat0' then
return
end
local s = iface['.name']
uci:set('network', s, 'proto', 'gluon_mesh')
uci:set('network', s, 'fixed_mtu', true)
if iface.mesh_no_rebroadcast then
uci:set('network', s, 'transitive', iface.mesh_no_rebroadcast)
end
uci:delete('network', s, 'mesh')
uci:delete('network', s, 'mesh_no_rebroadcast')
end
uci:foreach('network', 'interface', migrate_iface)
uci:save('network')
...@@ -12,13 +12,13 @@ uci:set('dhcp', dnsmasq, 'localise_queries', true) ...@@ -12,13 +12,13 @@ uci:set('dhcp', dnsmasq, 'localise_queries', true)
uci:set('dhcp', dnsmasq, 'localservice', false) uci:set('dhcp', dnsmasq, 'localservice', false)
uci:set('dhcp', dnsmasq, 'server', dns.servers) uci:set('dhcp', dnsmasq, 'server', dns.servers)
uci:delete('dhcp', dnsmasq, 'cachesize') uci:set('dhcp', dnsmasq, 'cachesize', dns.cacheentries)
uci:delete('firewall', 'client_dns') uci:delete('firewall', 'client_dns')
if dns.servers then if dns.servers then
-- allow inbound traffic for dns from client zone -- allow inbound traffic for dns from client zone
uci:section('firewall', 'rule', 'client_dns', { uci:section('firewall', 'rule', 'client_dns', {
src = 'local_client', src = 'loc_client',
dest_port = '53', dest_port = '53',
proto = 'tcpudp', proto = 'tcpudp',
target = 'ACCEPT', target = 'ACCEPT',
......
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
for _, config in ipairs({'system', 'network'}) do
uci:foreach(config .. '_gluon-old', nil, function(s)
if s.gluon_preserve ~= '1' then return end
-- Unnamed sections can't be preserved
if s['.anonymous'] then return end
-- We don't allow overwriting existing sections
if uci:get(config, s['.name']) then return end
uci:section(config, s['.type'], s['.name'], s)
end)
uci:save(config)
end
#!/usr/bin/lua
local info = require 'gluon.info'
local values = info.get_info_pretty()
local padTo = 24
for _, value in ipairs(values) do
local labelLen = string.len(value[1]) + 1
print(value[1] .. ':' .. string.rep(' ', padTo - labelLen), value[2])
end
#!/usr/bin/lua
local unistd = require 'posix.unistd'
local function shift()
table.remove(arg, 1)
end
local reboot = true
if arg[1] == '--no-reboot' then
reboot = false
shift()
end
local setup_mode = unistd.access('/var/gluon/setup-mode') == 0
if #arg ~= 1 then
io.stderr:write('Usage: gluon-switch-domain [--no-reboot] <domain>\n')
os.exit(1)
end
local domain = arg[1]
if not unistd.access('/lib/gluon/domains/') then
io.stderr:write('This Gluon firmware does not support multiple mesh domains.\n')
os.exit(1)
end
local function domain_exists(dom)
return unistd.access('/lib/gluon/domains/' .. dom .. '.json') == 0
end
if not domain_exists(domain) then
io.stderr:write(string.format("Error: invalid mesh domain '%s'\n", domain))
os.exit(1)
end
local uci = require('simple-uci').cursor()
uci:set('gluon', 'core', 'switch_domain', domain)
uci:set('gluon', 'core', 'reconfigure', true)
uci:save('gluon')
local cmd
if setup_mode then
cmd = 'gluon-reconfigure'
elseif reboot then
uci:commit('gluon')
cmd = 'reboot'
else
cmd = 'gluon-reload'
end
unistd.execp(cmd, {[0] = cmd})
local util = require 'gluon.util'
local unistd = require 'posix.unistd'
local dirent = require 'posix.dirent'
local uci = require('simple-uci').cursor()
local M = {}
local function has_devtype(iface_dir, devtype)
return util.file_contains_line(iface_dir..'/uevent', 'DEVTYPE='..devtype)
end
local function is_physical(iface_dir)
return unistd.access(iface_dir .. '/device') == 0
end
local function is_swconfig()
local has = false
uci:foreach("network", "switch", function()
has = true
end)
uci:foreach("network", "switch_vlan", function()
has = true
end)
return has
end
local function interfaces_raw()
local eth_ifaces = {}
local ifaces_dir = '/sys/class/net/'
for iface in dirent.files(ifaces_dir) do
if iface ~= '.' and iface ~= '..' then
local iface_dir = ifaces_dir .. iface
if is_physical(iface_dir) and not has_devtype(iface_dir, 'wlan') then
table.insert(eth_ifaces, iface)
end
end
end
return eth_ifaces
end
-- In comparison to interfaces_raw, this skips non-DSA ports on DSA devices,
-- as for ex. hap ac² has a special eth0 that shouldn't be touched
function M.interfaces()
local intfs = interfaces_raw()
if M.get_switch_type() == 'dsa' then
local new_intfs = {}
for _, intf in ipairs(intfs) do
if has_devtype('/sys/class/net/' .. intf, 'dsa') then
table.insert(new_intfs, intf)
end
end
return new_intfs
end
return intfs
end
function M.is_vlan(intf)
return has_devtype('/sys/class/net/' .. intf, 'vlan')
end
function M.get_switch_type()
if is_swconfig() then
return 'swconfig'
end
for _, intf in ipairs(interfaces_raw()) do
if has_devtype('/sys/class/net/' .. intf, 'dsa') then
return 'dsa'
end
end
return 'none'
end
return M
local uci = require('simple-uci').cursor()
local pretty_hostname = require 'pretty_hostname'
local site = require 'gluon.site'
local sysconfig = require 'gluon.sysconfig'
local platform = require 'gluon.platform'
local util = require 'gluon.util'
local has_vpn, vpn = pcall(require, 'gluon.mesh-vpn')
local ethernet = require 'gluon.ethernet'
local pubkey
if has_vpn and vpn.enabled() then
local _, active_vpn = vpn.get_active_provider()
if active_vpn ~= nil then
pubkey = active_vpn.public_key()
end
end
local M = {}
function M.get_info()
local updater_enabled = uci:get_bool('autoupdater', 'settings', 'enabled')
return {
hostname = pretty_hostname.get(uci),
mac_address = sysconfig.primary_mac,
hardware_model = platform.get_model(),
gluon_version = util.trim(util.readfile('/lib/gluon/gluon-version')),
site_version = util.trim(util.readfile('/lib/gluon/site-version')),
firmware_release = util.trim(util.readfile('/lib/gluon/release')),
site = site.site_name(),
domain = uci:get('gluon', 'core', 'domain'),
public_vpn_key = pubkey,
switch_type = ethernet.get_switch_type(),
updater_branch = updater_enabled and uci:get('autoupdater', 'settings', 'branch'),
}
end
function M.get_info_pretty(i18n)
local _
if i18n then
local pkg_i18n = i18n 'gluon-core'
_ = function(s)
return pkg_i18n.translate(s)
end
else
_ = function(s)
return s
end
end
local data = M.get_info()
return {
{ _('Hostname'), data.hostname },
{ _('MAC address'), data.mac_address },
{ _('Hardware model'), data.hardware_model },
{ _('Gluon version') .. " / " .. _('Site version'), data.gluon_version .. " / " .. data.site_version },
{ _('Firmware release'), data.firmware_release },
{ _('Site'), data.site },
{ _('Domain'), data.domain or 'n/a' },
{ _('Public VPN key'), data.public_vpn_key or _('disabled') },
{ _('Switch type'), data.switch_type },
{ _('Autoupdater branch'), data.updater_branch or _('disabled') },
}
end
return M
local bit = require 'bit' local bit = require 'bit32'
local M = {} local M = {}
...@@ -74,10 +74,10 @@ function M.IPv6(address) ...@@ -74,10 +74,10 @@ function M.IPv6(address)
end end
end end
function M.mac_to_ip(prefix, mac) function M.mac_to_ip(prefix, mac, firstbyte, secondbyte)
local m1, m2, m3, m6, m7, m8 = string.match(mac, '(%x%x):(%x%x):(%x%x):(%x%x):(%x%x):(%x%x)') local m1, m2, m3, m6, m7, m8 = string.match(mac, '(%x%x):(%x%x):(%x%x):(%x%x):(%x%x):(%x%x)')
local m4 = 0xff local m4 = firstbyte or 0xff
local m5 = 0xfe local m5 = secondbyte or 0xfe
m1 = bit.bxor(tonumber(m1, 16), 0x02) m1 = bit.bxor(tonumber(m1, 16), 0x02)
local h1 = 0x100 * m1 + tonumber(m2, 16) local h1 = 0x100 * m1 + tonumber(m2, 16)
......
...@@ -7,11 +7,11 @@ local M = setmetatable({}, { ...@@ -7,11 +7,11 @@ local M = setmetatable({}, {
}) })
function M.match(target, subtarget, boards) function M.match(target, subtarget, boards)
if M.get_target() ~= target then if target and M.get_target() ~= target then
return false return false
end end
if M.get_subtarget() ~= subtarget then if subtarget and M.get_subtarget() ~= subtarget then
return false return false
end end
...@@ -23,26 +23,86 @@ function M.match(target, subtarget, boards) ...@@ -23,26 +23,86 @@ function M.match(target, subtarget, boards)
end end
function M.is_outdoor_device() function M.is_outdoor_device()
if M.match('ar71xx', 'generic', { if M.match('ath79', 'generic', {
'bullet-m', 'devolo,dvl1750x',
'cpe510', 'librerouter,librerouter-v1',
'lbe-m5', 'plasmacloud,pa300',
'loco-m-xw', 'plasmacloud,pa300e',
'nanostation-m', 'tplink,cpe210-v1',
'nanostation-m-xw', 'tplink,cpe210-v2',
'rocket-m', 'tplink,cpe210-v3',
'rocket-m-ti', 'tplink,cpe220-v3',
'rocket-m-xw', 'tplink,cpe510-v1',
'unifi-outdoor', 'tplink,cpe510-v2',
'tplink,cpe510-v3',
'tplink,cpe710-v1',
'tplink,eap225-outdoor-v1',
'tplink,eap225-outdoor-v3',
'tplink,wbs210-v1',
'tplink,wbs210-v2',
'tplink,wbs510-v1',
'ubnt,nanobeam-ac-xc',
'ubnt,nanobeam-m5-xw',
'ubnt,nanostation-loco-m-xw',
'ubnt,nanostation-m-xw',
'ubnt,uk-ultra',
'ubnt,unifi-ap-outdoor-plus',
'ubnt,unifiac-mesh',
'ubnt,unifiac-mesh-pro',
}) then }) then
return true return true
elseif M.match('ar71xx', 'generic', {'unifiac-lite'}) and elseif M.match('ath79', 'mikrotik', {
M.get_model() == 'Ubiquiti UniFi-AC-MESH' then 'mikrotik,routerboard-wapr-2nd',
}) then
return true
elseif M.match('ipq40xx', 'generic', {
'aruba,ap-365',
'plasmacloud,pa1200',
}) then
return true
elseif M.match('ipq40xx', 'mikrotik', {
'mikrotik,sxtsq-5-ac',
}) then
return true
elseif M.match('mediatek', 'filogic', {
'cudy,ap3000outdoor-v1',
'wavlink,wl-wn573hx3',
}) then
return true
elseif M.match('ramips', 'mt7621', {
'wavlink,ws-wn572hp3-4g',
'zyxel,nwa55axe',
}) then
return true return true
end
return false
end
elseif M.match('ar71xx', 'generic', {'unifiac-pro'}) and function M.is_cellular_device()
M.get_model() == 'Ubiquiti UniFi-AC-MESH-PRO' then if M.match('ath79', 'nand', {
'zte,mf281',
'glinet,gl-e750',
'glinet,gl-xe300',
}) then
return true
elseif M.match('ipq40xx', 'generic', {
'glinet,gl-ap1300',
'zte,mf289f',
}) then
return true
elseif M.match('ramips', 'mt7621', {
'wavlink,ws-wn572hp3-4g',
}) then
return true
elseif M.match('ramips', 'mt76x8', {
'tplink,tl-mr6400-v5',
}) then
return true return true
end end
......
...@@ -11,6 +11,10 @@ local function get(_, name) ...@@ -11,6 +11,10 @@ local function get(_, name)
end end
local function set(_, name, val) local function set(_, name, val)
if val == get(nil, name) then
return
end
if val then if val then
local f = io.open(sysconfigdir .. name, 'w+') local f = io.open(sysconfigdir .. name, 'w+')
f:write(val, '\n') f:write(val, '\n')
......
local bit = require 'bit' local bit = require 'bit32'
local posix_fcntl = require 'posix.fcntl'
local posix_glob = require 'posix.glob' local posix_glob = require 'posix.glob'
local posix_syslog = require 'posix.syslog'
local posix_unistd = require 'posix.unistd'
local hash = require 'hash' local hash = require 'hash'
local sysconfig = require 'gluon.sysconfig' local sysconfig = require 'gluon.sysconfig'
local site = require 'gluon.site' local site = require 'gluon.site'
local unistd = require 'posix.unistd'
local M = {} local M = {}
...@@ -23,7 +27,7 @@ local function do_filter_prefix(input, output, prefix) ...@@ -23,7 +27,7 @@ local function do_filter_prefix(input, output, prefix)
end end
function M.trim(str) function M.trim(str)
return str:gsub("^%s*(.-)%s*$", "%1") return (str:gsub("^%s*(.-)%s*$", "%1"))
end end
function M.contains(table, value) function M.contains(table, value)
...@@ -35,6 +39,19 @@ function M.contains(table, value) ...@@ -35,6 +39,19 @@ function M.contains(table, value)
return false return false
end end
function M.file_contains_line(path, value)
if not unistd.access(path) then
return false
end
for line in io.lines(path) do
if line == value then
return true
end
end
return false
end
function M.add_to_set(t, itm) function M.add_to_set(t, itm)
for _,v in ipairs(t) do for _,v in ipairs(t) do
if v == itm then return false end if v == itm then return false end
...@@ -87,7 +104,7 @@ function M.exec(command) ...@@ -87,7 +104,7 @@ function M.exec(command)
end end
function M.node_id() function M.node_id()
return string.gsub(sysconfig.primary_mac, ':', '') return (string.gsub(sysconfig.primary_mac, ':', ''))
end end
function M.default_hostname() function M.default_hostname()
...@@ -121,49 +138,39 @@ function M.get_mesh_devices(uconn) ...@@ -121,49 +138,39 @@ function M.get_mesh_devices(uconn)
return devices return devices
end end
-- Safe glob: returns an empty table when the glob fails because of -- Returns a list of all interfaces with a given role
-- a non-existing path --
function M.glob(pattern) -- If exclusive is set to true, only interfaces that have no other role
return posix_glob.glob(pattern) or {} -- are returned; this is used to ensure that the client role is not active
end -- at the same time as any other role
function M.get_role_interfaces(uci, role, exclusive)
local function find_phy_by_path(path) local ret = {}
local phy = M.glob('/sys/devices/' .. path .. '/ieee80211/phy*')[1]
or M.glob('/sys/devices/platform/' .. path .. '/ieee80211/phy*')[1]
if phy then
return phy:match('([^/]+)$')
end
end
local function find_phy_by_macaddr(macaddr) local function add(name)
local addr = macaddr:lower() -- Interface names with a / prefix refer to sysconfig interfaces
for _, file in ipairs(M.glob('/sys/class/ieee80211/*/macaddress')) do -- (lan_ifname/wan_ifname/single_ifname)
if M.trim(M.readfile(file)) == addr then if string.sub(name, 1, 1) == '/' then
return file:match('([^/]+)/macaddress$') name = sysconfig[string.sub(name, 2) .. '_ifname'] or ''
end end
for iface in string.gmatch(name, '%S+') do
M.add_to_set(ret, iface)
end end
end end
function M.find_phy(config) uci:foreach('gluon', 'interface', function(s)
if not config or config.type ~= 'mac80211' then local roles = s.role or {}
return nil if M.contains(roles, role) and (not exclusive or #roles == 1) then
elseif config.path then add(s.name)
return find_phy_by_path(config.path)
elseif config.macaddr then
return find_phy_by_macaddr(config.macaddr)
else
return nil
end
end end
end)
local function get_addresses(radio) return ret
local phy = M.find_phy(radio)
if not phy then
return function() end
end end
return io.lines('/sys/class/ieee80211/' .. phy .. '/addresses') -- Safe glob: returns an empty table when the glob fails because of
-- a non-existing path
function M.glob(pattern)
return posix_glob.glob(pattern, 0) or {}
end end
-- Generates a (hopefully) unique MAC address -- Generates a (hopefully) unique MAC address
...@@ -172,11 +179,11 @@ end ...@@ -172,11 +179,11 @@ end
-- IDs defined so far: -- IDs defined so far:
-- 0: client0; WAN -- 0: client0; WAN
-- 1: mesh0 -- 1: mesh0
-- 2: ibss0 -- 2: owe0
-- 3: wan_radio0 (private WLAN); batman-adv primary address -- 3: wan_radio0 (private WLAN); batman-adv primary address
-- 4: client1; LAN -- 4: client1; LAN
-- 5: mesh1 -- 5: mesh1
-- 6: ibss1 -- 6: owe1
-- 7: wan_radio1 (private WLAN); mesh VPN -- 7: wan_radio1 (private WLAN); mesh VPN
function M.generate_mac(i) function M.generate_mac(i)
if i > 7 or i < 0 then return nil end -- max allowed id (0b111) if i > 7 or i < 0 then return nil end -- max allowed id (0b111)
...@@ -200,65 +207,103 @@ function M.generate_mac(i) ...@@ -200,65 +207,103 @@ function M.generate_mac(i)
return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6) return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6)
end end
local function get_wlan_mac_from_driver(radio, vif) function M.get_uptime()
local primary = sysconfig.primary_mac:lower() local uptime_file = M.readfile("/proc/uptime")
if uptime_file == nil then
local addresses = {} -- Something went wrong reading "/proc/uptime"
for address in get_addresses(radio) do return nil
if address:lower() ~= primary then
table.insert(addresses, address)
end end
return tonumber(uptime_file:match('^[^ ]+'))
end end
-- Make sure we have at least 4 addresses function M.log(message, verbose)
if #addresses < 4 then if verbose then
return nil io.stdout:write(message .. '\n')
end end
for i, addr in ipairs(addresses) do posix_syslog.syslog(posix_syslog.LOG_INFO, message)
if i == vif then
return addr
end end
local function close_fds(fds)
for _, fd in pairs(fds) do
posix_unistd.close(fd)
end end
end end
function M.get_wlan_mac(_, radio, index, vif) M.subprocess = {}
local addr = get_wlan_mac_from_driver(radio, vif)
if addr then M.subprocess.DEVNULL = -1
return addr M.subprocess.PIPE = 1
end
return M.generate_mac(4*(index-1) + (vif-1)) -- Execute a program found using command PATH search, like the shell.
-- Return the pid, as well as the I/O streams as pipes or nil on error.
function M.subprocess.popen(path, argt, options)
argt = argt or {}
local childfds = {}
local parentfds = {}
local stdiostreams = {stdin = 0, stdout = 1, stderr = 2}
for iostream in pairs(stdiostreams) do
if options[iostream] == M.subprocess.PIPE then
local piper, pipew = posix_unistd.pipe()
if iostream == "stdin" then
childfds[iostream] = piper
parentfds[iostream] = pipew
else
childfds[iostream] = pipew
parentfds[iostream] = piper
end
end
end end
-- Iterate over all radios defined in UCI calling -- childfds: r0, w1, w2
-- f(radio, index, site.wifiX) for each radio found while passing -- parentfds: w0, r1, r2
-- site.wifi24 for 2.4 GHz devices and site.wifi5 for 5 GHz ones.
function M.foreach_radio(uci, f)
local radios = {}
uci:foreach('wireless', 'wifi-device', function(radio) local pid, errmsg, errnum = posix_unistd.fork()
table.insert(radios, radio)
end)
for index, radio in ipairs(radios) do if pid == nil then
local hwmode = radio.hwmode close_fds(parentfds)
close_fds(childfds)
return nil, errmsg, errnum
elseif pid == 0 then
local null = -1
if M.contains(options, M.subprocess.DEVNULL) then
-- only open if there's anything to discard
null = posix_fcntl.open('/dev/null', posix_fcntl.O_RDWR)
end
if hwmode == '11g' or hwmode == '11ng' then for iostream, fd in pairs(stdiostreams) do
f(radio, index, site.wifi24) local option = options[iostream]
elseif hwmode == '11a' or hwmode == '11na' then if option == M.subprocess.DEVNULL then
f(radio, index, site.wifi5) posix_unistd.dup2(null, fd)
elseif option == M.subprocess.PIPE then
posix_unistd.dup2(childfds[iostream], fd)
end end
end end
close_fds(childfds)
close_fds(parentfds)
-- close potential null
if null > 2 then
posix_unistd.close(null)
end end
function M.get_uptime() posix_unistd.execp(path, argt)
local uptime_file = M.readfile("/proc/uptime") posix_unistd._exit(127)
if uptime_file == nil then end
-- Something went wrong reading "/proc/uptime"
return nil close_fds(childfds)
return pid, parentfds
end
function M.get_mem_total()
for line in io.lines('/proc/meminfo') do
local match = line:match('^MemTotal:%s+(%d+)')
if match then
return tonumber(match)
end
end end
return tonumber(uptime_file:match('^[^ ]+'))
end end
return M return M
local sysconfig = require 'gluon.sysconfig'
local site = require 'gluon.site'
local util = require 'gluon.util'
local unistd = require 'posix.unistd'
local iwinfo = require 'iwinfo'
local M = {}
function M.find_phy(config)
return iwinfo.nl80211.phyname(config['.name'])
end
local function get_addresses(radio)
local phy = M.find_phy(radio)
if not phy then
return function() end
end
return io.lines('/sys/class/ieee80211/' .. phy .. '/addresses')
end
local function get_wlan_mac_from_driver(radio, vif)
local primary = sysconfig.primary_mac:lower()
local addresses = {}
for address in get_addresses(radio) do
if address:lower() ~= primary then
table.insert(addresses, address)
end
end
-- Make sure we have at least 4 addresses
if #addresses < 4 then
return nil
end
return addresses[vif]
end
function M.get_wlan_mac(_, radio, index, vif)
local addr = get_wlan_mac_from_driver(radio, vif)
if addr then
return addr
end
return util.generate_mac(4*(index-1) + (vif-1))
end
-- Iterate over all radios defined in UCI calling
-- f(radio, index, site.wifiX) for each radio found while passing
-- site.wifi24 for 2.4 GHz devices and site.wifi5 for 5 GHz ones.
function M.foreach_radio(uci, f)
local radios = {}
uci:foreach('wireless', 'wifi-device', function(radio)
table.insert(radios, radio)
end)
for index, radio in ipairs(radios) do
local band = radio.band
if band == '2g' then
f(radio, index, site.wifi24)
elseif band == '5g' then
f(radio, index, site.wifi5)
end
end
end
function M.preserve_channels(uci)
return uci:get_bool('gluon', 'wireless', 'preserve_channels')
end
function M.device_supports_wpa3()
return unistd.access('/lib/gluon/features/wpa3')
end
function M.device_supports_mfp(uci)
local supports_mfp = true
if not M.device_supports_wpa3() then
return false
end
uci:foreach('wireless', 'wifi-device', function(radio)
local phy = M.find_phy(radio)
local phypath = '/sys/kernel/debug/ieee80211/' .. phy .. '/'
if not util.file_contains_line(phypath .. 'hwflags', 'MFP_CAPABLE') then
supports_mfp = false
return false
end
end)
return supports_mfp
end
function M.device_uses_wlan(uci)
local ret = false
uci:foreach('wireless', 'wifi-device', function()
ret = true
return false
end)
return ret
end
function M.device_uses_11a(uci)
local ret = false
uci:foreach('wireless', 'wifi-device', function(radio)
if radio.band == '5g' then
ret = true
return false
end
end)
return ret
end
return M