gluon-core: add outdoor support for 5 ghz radios
Add the `wifi5.outdoor_chanlist` site configuration that allows specifying an outdoor channel range that can be switched to for regulatory compliance. Upon enabling the outdoor option the device will - configure the `outdoor_chanlist` on all 5 GHz radios - which may enable DFS/TPC, based on the regulatory domain - disable ibss/mesh on the 5 GHz radio, as DFS *will* break mesh connections - allow for htmode reconfiguration on 5 GHz radios The outdoor option can be toggled from - Advanced Settings - W-LAN - Outdoor Installation The `preserve_channel` flag overrules the outdoor channel selection.
This commit is contained in:
parent
4f60f6dbc6
commit
bf55249159
@ -61,6 +61,7 @@
|
||||
-- for channel.
|
||||
wifi5 = {
|
||||
channel = 44,
|
||||
outdoor_chanlist = '100-140',
|
||||
ap = {
|
||||
ssid = 'alpha-centauri.freifunk.net',
|
||||
},
|
||||
|
@ -166,6 +166,21 @@ wifi24 \: optional
|
||||
wifi5 \: optional
|
||||
Same as `wifi24` but for the 5Ghz radio.
|
||||
|
||||
Additionally a range of channels that are safe to use outsides on the 5 GHz band can
|
||||
be set up through ``outdoor_chanlist``, which allows for a space-seperated list of
|
||||
channels and channel ranges, seperated by a hyphen.
|
||||
When set this offers the outdoor mode flag for 5 GHz radios in the config mode which
|
||||
reconfigures the AP to select its channel from outdoor chanlist, while respecting
|
||||
regulatory specifications, and disables mesh on that radio.
|
||||
::
|
||||
|
||||
wifi5 = {
|
||||
channel = 44,
|
||||
outdoor_chanlist = "100-140",
|
||||
|
||||
[...]
|
||||
},
|
||||
|
||||
next_node \: package
|
||||
Configuration of the local node feature of Gluon
|
||||
::
|
||||
|
@ -34,6 +34,9 @@ for _, config in ipairs({'wifi24', 'wifi5'}) do
|
||||
need_string(in_site({'regdom'})) -- regdom is only required when wifi24 or wifi5 is configured
|
||||
|
||||
need_number({config, 'channel'})
|
||||
if config == 'wifi5' then
|
||||
need_string_match({config, 'outdoor_chanlist'}, '^[%d%s-]+$', false)
|
||||
end
|
||||
|
||||
obsolete({config, 'supported_rates'}, '802.11b rates are disabled by default.')
|
||||
obsolete({config, 'basic_rate'}, '802.11b rates are disabled by default.')
|
||||
|
@ -49,22 +49,37 @@ if not sysconfig.gluon_version then
|
||||
end)
|
||||
end
|
||||
|
||||
local function is_outdoor()
|
||||
return uci:get_bool('gluon', 'wireless', 'outdoor')
|
||||
end
|
||||
|
||||
local function get_channel(radio, config)
|
||||
local channel
|
||||
if uci:get_first('gluon-core', 'wireless', 'preserve_channels') then
|
||||
-- preserved channel always wins
|
||||
channel = radio.channel
|
||||
elseif (radio.hwmode == '11a' or radio.hwmode == '11na') 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)
|
||||
local phy = util.find_phy(radio)
|
||||
if iwinfo.nl80211.hwmodelist(phy).ac then
|
||||
return 'VHT20'
|
||||
else
|
||||
return 'HT20'
|
||||
end
|
||||
if (radio.hwmode == '11a' or radio.hwmode == '11na') 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 = util.find_phy(radio)
|
||||
if iwinfo.nl80211.hwmodelist(phy).ac then
|
||||
return 'VHT20'
|
||||
end
|
||||
|
||||
return 'HT20'
|
||||
end
|
||||
|
||||
local function is_disabled(name)
|
||||
@ -207,31 +222,49 @@ util.foreach_radio(uci, function(radio, index, config)
|
||||
uci:set('wireless', radio_name, 'htmode', htmode)
|
||||
uci:set('wireless', radio_name, 'country', site.regdom())
|
||||
|
||||
local hwmode = radio.hwmode
|
||||
if hwmode == '11g' or hwmode == '11ng' then
|
||||
uci:set('wireless', radio_name, 'legacy_rates', false)
|
||||
end
|
||||
|
||||
uci:delete('wireless', radio_name, 'supported_rates')
|
||||
uci:delete('wireless', radio_name, 'basic_rate')
|
||||
|
||||
local ibss_disabled = is_disabled('ibss_' .. radio_name)
|
||||
local mesh_disabled = is_disabled('mesh_' .. radio_name)
|
||||
local hwmode = radio.hwmode
|
||||
if hwmode == '11g' or hwmode == '11ng' then
|
||||
uci:set('wireless', radio_name, 'legacy_rates', false)
|
||||
elseif (hwmode == '11a' or hwmode == '11na') then
|
||||
if is_outdoor() then
|
||||
uci:set('wireless', radio_name, 'channels', config.outdoor_chanlist())
|
||||
|
||||
configure_ibss(config.ibss(), radio, index, suffix,
|
||||
first_non_nil(
|
||||
ibss_disabled,
|
||||
mesh_disabled,
|
||||
config.ibss.disabled(false)
|
||||
)
|
||||
)
|
||||
configure_mesh(config.mesh(), radio, index, suffix,
|
||||
first_non_nil(
|
||||
mesh_disabled,
|
||||
ibss_disabled,
|
||||
config.mesh.disabled(false)
|
||||
)
|
||||
)
|
||||
-- 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)
|
||||
|
||||
uci:delete('wireless', 'ibss_' .. radio_name)
|
||||
uci:delete('wireless', 'mesh_' .. radio_name)
|
||||
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)
|
||||
|
||||
local ibss_disabled = is_disabled('ibss_' .. radio_name)
|
||||
local mesh_disabled = is_disabled('mesh_' .. radio_name)
|
||||
|
||||
configure_ibss(config.ibss(), radio, index, suffix,
|
||||
first_non_nil(
|
||||
ibss_disabled,
|
||||
mesh_disabled,
|
||||
config.ibss.disabled(false)
|
||||
)
|
||||
)
|
||||
configure_mesh(config.mesh(), radio, index, suffix,
|
||||
first_non_nil(
|
||||
mesh_disabled,
|
||||
ibss_disabled,
|
||||
config.mesh.disabled(false)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
fixup_wan(radio, index)
|
||||
end)
|
||||
|
@ -49,3 +49,25 @@ msgstr ""
|
||||
"werden. Wenn möglich, ist in den Werten der Sendeleistung der Antennengewinn "
|
||||
"enthalten; diese Werte sind allerdings für viele Geräte nicht verfügbar oder "
|
||||
"fehlerhaft."
|
||||
|
||||
msgid "Outdoor installation"
|
||||
msgstr "Outdoor-Installation"
|
||||
|
||||
msgid "Node will be installed outdoors"
|
||||
msgstr "Knoten wird im Außenbereich betrieben"
|
||||
|
||||
msgid ""
|
||||
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
|
||||
"and transmission power that conforms with the local regulatory requirements. "
|
||||
"It also enables dynamic frequency selection (DFS; radar detection). At the "
|
||||
"same time, mesh functionality is disabled as it requires neighbouring nodes "
|
||||
"to stay on the same channel permanently."
|
||||
msgstr ""
|
||||
"Ist der Knoten für den Einsatz im Freien konfiguriert, wird ein WLAN-Kanal auf "
|
||||
"dem 5-GHz-Band sowie eine Sendeleistung entsprechend den gesetzlichen "
|
||||
"Frequenzregulatorien gewählt. Gleichzeitig wird die dynamische Frequenzwahl "
|
||||
"(DFS; Radarerkennung) aktiviert und die Mesh-Funktionalität deaktiviert, da "
|
||||
"sich Nachbarknoten dauerhaft auf demselben Kanal befinden müssen."
|
||||
|
||||
msgid "HT Mode"
|
||||
msgstr "HT-Modus"
|
||||
|
@ -46,3 +46,9 @@ msgstr ""
|
||||
"<br /><br />Ici vous pouvez aussi configurer la puissance d'émmission se votre Wi-Fi. "
|
||||
"Prenez note que les valeurs fournies pour la puissance de transmission prennent "
|
||||
"en compte les gains fournis par l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
|
||||
|
||||
msgid "Outdoor installation"
|
||||
msgstr "Installation extérieure"
|
||||
|
||||
msgid "HT Mode"
|
||||
msgstr "Mode HT"
|
||||
|
@ -33,3 +33,20 @@ msgid ""
|
||||
"values include the antenna gain where available, but there are many devices "
|
||||
"for which the gain is unavailable or inaccurate."
|
||||
msgstr ""
|
||||
|
||||
msgid "Outdoor installation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Node will be installed outdoors"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
|
||||
"and transmission power that conforms with the local regulatory requirements. "
|
||||
"It also enables dynamic frequency selection (DFS; radar detection). At the "
|
||||
"same time, mesh functionality is disabled as it requires neighbouring nodes "
|
||||
"to stay on the same channel permanently."
|
||||
msgstr ""
|
||||
|
||||
msgid "HT Mode"
|
||||
msgstr ""
|
||||
|
@ -1,4 +1,5 @@
|
||||
local iwinfo = require 'iwinfo'
|
||||
local site = require 'gluon.site'
|
||||
local uci = require("simple-uci").cursor()
|
||||
local util = require 'gluon.util'
|
||||
|
||||
@ -8,7 +9,6 @@ local function txpower_list(phy)
|
||||
local off = tonumber(iwinfo.nl80211.txpower_offset(phy)) or 0
|
||||
local new = { }
|
||||
local prev = -1
|
||||
local _, val
|
||||
for _, val in ipairs(list) do
|
||||
local dbm = val.dbm + off
|
||||
local mw = math.floor(10 ^ (dbm / 10))
|
||||
@ -24,6 +24,17 @@ local function txpower_list(phy)
|
||||
return new
|
||||
end
|
||||
|
||||
local function has_5ghz_radio()
|
||||
local result = false
|
||||
uci:foreach('wireless', 'wifi-device', function(config)
|
||||
local radio = config['.name']
|
||||
local hwmode = uci:get('wireless', radio, 'hwmode')
|
||||
|
||||
result = result or (hwmode == '11a' or hwmode == '11na')
|
||||
end)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local f = Form(translate("WLAN"))
|
||||
|
||||
@ -97,7 +108,57 @@ uci:foreach('wireless', 'wifi-device', function(config)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
if has_5ghz_radio() then
|
||||
local r = f:section(Section, translate("Outdoor Installation"), translate(
|
||||
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
|
||||
.. "and transmission power that conforms with the local regulatory requirements. "
|
||||
.. "It also enables dynamic frequency selection (DFS; radar detection). At the "
|
||||
.. "same time, mesh functionality is disabled as it requires neighbouring nodes "
|
||||
.. "to stay on the same channel permanently."
|
||||
))
|
||||
|
||||
local outdoor = r:option(Flag, 'outdoor', translate("Node will be installed outdoors"))
|
||||
outdoor.default = uci:get_bool('gluon', 'wireless', 'outdoor')
|
||||
|
||||
function outdoor:write(data)
|
||||
uci:set('gluon', 'wireless', 'outdoor', data)
|
||||
end
|
||||
|
||||
uci:foreach('wireless', 'wifi-device', function(config)
|
||||
local radio = config['.name']
|
||||
local hwmode = uci:get('wireless', radio, 'hwmode')
|
||||
|
||||
if hwmode ~= '11a' and hwmode ~= '11na' then
|
||||
return
|
||||
end
|
||||
|
||||
local phy = util.find_phy(uci:get_all('wireless', radio))
|
||||
|
||||
local ht = r:option(ListValue, 'outdoor_htmode', translate('HT Mode') .. ' (' .. radio .. ')')
|
||||
ht:depends(outdoor, true)
|
||||
ht.default = uci.get('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode') or 'default'
|
||||
|
||||
ht:value('default', translate("(default)"))
|
||||
for mode, available in pairs(iwinfo.nl80211.htmodelist(phy)) do
|
||||
if available then
|
||||
ht:value(mode, mode)
|
||||
end
|
||||
end
|
||||
|
||||
function ht:write(data)
|
||||
if data == 'default' then
|
||||
data = nil
|
||||
end
|
||||
uci:set('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode', data)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
function f:write()
|
||||
uci:commit('gluon')
|
||||
os.execute('/lib/gluon/upgrade/200-wireless')
|
||||
uci:commit('wireless')
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user