gluon-firmware/package/gluon-core/luasrc/lib/gluon/upgrade/200-wireless

248 lines
6.4 KiB
Lua
Executable File

#!/usr/bin/lua
local util = require 'gluon.util'
local wireless = require 'gluon.wireless'
local site = require 'gluon.site'
local sysconfig = require 'gluon.sysconfig'
local iwinfo = require 'iwinfo'
local uci = require('simple-uci').cursor()
-- Initial
if not sysconfig.gluon_version then
uci:delete_all('wireless', 'wifi-iface')
-- First count all radios with a fixed frequency band.
-- This is needed to distribute devices which have radios
-- capable of operating in the 2.4 GHz and 5 GHz band need
-- to be distributed evenly.
local radio_band_count = {band24=0, band5=0}
wireless.foreach_radio(uci, function(radio)
local hwmodes = iwinfo.nl80211.hwmodelist(wireless.find_phy(radio))
if hwmodes.g and not (hwmodes.a or hwmodes.ac) then
-- 2.4 GHz
radio_band_count["band24"] = radio_band_count["band24"] + 1
elseif (hwmodes.a or hwmodes.ac) and not hwmodes.g then
-- 5 GHz
radio_band_count["band5"] = radio_band_count["band5"] + 1
end
end)
-- Use the number of all fixed 2.4G GHz and 5 GHz radios to
-- distribute dualband radios in this step.
wireless.foreach_radio(uci, function(radio)
local radio_name = radio['.name']
local hwmodes = iwinfo.nl80211.hwmodelist(wireless.find_phy(radio))
if (hwmodes.a or hwmodes.ac) and hwmodes.g then
-- Dualband radio
if radio_band_count["band24"] <= radio_band_count["band5"] then
-- Assign radio to 2.4GHz band
radio_band_count["band24"] = radio_band_count["band24"] + 1
uci:set('wireless', radio_name, 'band', '2g')
else
-- Assign radio to 5GHz band
radio_band_count["band5"] = radio_band_count["band5"] + 1
uci:set('wireless', radio_name, 'band', '5g')
end
end
end)
end
local function is_outdoor()
return uci:get_bool('gluon', 'wireless', 'outdoor')
end
local function get_channel(radio, config)
local channel
if wireless.preserve_channels(uci) then
-- preserved channel always wins
channel = radio.channel
elseif radio.band == '5g' and is_outdoor() then
-- actual channel will be picked and probed from chanlist
channel = 'auto'
end
return channel or config.channel()
end
local function get_htmode(radio)
if radio.band == '5g' and is_outdoor() then
local outdoor_htmode = uci:get('gluon', 'wireless', 'outdoor_' .. radio['.name'] .. '_htmode')
if outdoor_htmode ~= nil then
return outdoor_htmode
end
end
local phy = wireless.find_phy(radio)
if iwinfo.nl80211.hwmodelist(phy).ax then
return 'HE20'
end
if iwinfo.nl80211.hwmodelist(phy).ac then
return 'VHT20'
end
return 'HT20'
end
local function is_disabled(name)
if not uci:get('wireless', name) then
return nil
end
return uci:get_bool('wireless', name, 'disabled')
end
-- Returns the first argument that is not nil; don't call without any non-nil arguments!
local function first_non_nil(first, ...)
if first ~= nil then
return first
end
return first_non_nil(...)
end
local function delete_ibss(radio_name)
local name = 'ibss_' .. radio_name
uci:delete('network', name)
uci:delete('network', name .. '_vlan')
uci:delete('wireless', name)
end
local function configure_mesh(config, radio, index, suffix, disabled)
local radio_name = radio['.name']
local name = 'mesh_' .. radio_name
local macfilter = uci:get('wireless', name, 'macfilter')
local maclist = uci:get('wireless', name, 'maclist')
uci:delete('network', name)
uci:delete('network', name .. '_vlan')
uci:delete('wireless', name)
if not config then
return
end
local macaddr = wireless.get_wlan_mac(uci, radio, index, 2)
if not macaddr then
return
end
uci:section('network', 'interface', name, {
proto = 'gluon_mesh',
})
uci:section('wireless', 'wifi-iface', name, {
device = radio_name,
network = name,
mode = 'mesh',
mesh_id = config.id,
mesh_fwding = false,
macaddr = macaddr,
mcast_rate = config.mcast_rate,
ifname = suffix and 'mesh' .. suffix,
disabled = disabled,
macfilter = macfilter,
maclist = maclist,
})
end
local function fixup_wan(radio, index)
local radio_name = radio['.name']
local name = 'wan_' .. radio_name
if not uci:get('wireless', name) then
return
end
local macaddr = wireless.get_wlan_mac(uci, radio, index, 4)
if not macaddr then
return
end
uci:set('wireless', name, 'macaddr', macaddr)
end
local function configure_mesh_wireless(radio, index, config, disabled)
local radio_name = radio['.name']
local suffix = radio_name:match('^radio(%d+)$')
configure_mesh(config.mesh(), radio, index, suffix,
first_non_nil(
disabled,
is_disabled('mesh_' .. radio_name),
config.mesh.disabled(false)
)
)
end
wireless.foreach_radio(uci, function(radio, index, config)
local radio_name = radio['.name']
delete_ibss(radio_name)
if not config() then
uci:set('wireless', radio_name, 'disabled', true)
return
end
local suffix = radio_name:match('^radio(%d+)$')
if not suffix then
return
end
local channel = get_channel(radio, config)
local htmode = get_htmode(radio)
local beacon_interval = config.beacon_interval()
uci:delete('wireless', radio_name, 'disabled')
uci:set('wireless', radio_name, 'channel', channel)
uci:set('wireless', radio_name, 'htmode', htmode)
uci:set('wireless', radio_name, 'country', site.regdom())
uci:delete('wireless', radio_name, 'supported_rates')
uci:delete('wireless', radio_name, 'basic_rate')
local band = radio.band
if band == '2g' then
uci:set('wireless', radio_name, 'legacy_rates', false)
configure_mesh_wireless(radio, index, config)
elseif (band == '5g') then
if is_outdoor() then
uci:set('wireless', radio_name, 'channels', config.outdoor_chanlist())
-- enforce outdoor channels by filtering the regdom for outdoor channels
local hostapd_options = uci:get_list('wireless', radio_name, 'hostapd_options')
util.add_to_set(hostapd_options, 'country3=0x4f')
uci:set_list('wireless', radio_name, 'hostapd_options', hostapd_options)
configure_mesh_wireless(radio, index, config, true)
else
uci:delete('wireless', radio_name, 'channels')
local hostapd_options = uci:get_list('wireless', radio_name, 'hostapd_options')
util.remove_from_set(hostapd_options, 'country3=0x4f')
uci:set_list('wireless', radio_name, 'hostapd_options', hostapd_options)
configure_mesh_wireless(radio, index, config)
end
end
uci:set('wireless', radio_name, 'beacon_int', beacon_interval)
fixup_wan(radio, index)
end)
if uci:get('system', 'rssid_wlan0') then
uci:set('system', 'rssid_wlan0', 'dev', 'mesh0')
uci:save('system')
end
uci:save('wireless')
uci:save('network')