Remove hardwired frequency tables and use information from the hardware (#801)

* Remove hard coded channel tables
* Reduce radios.json to only what's needed
* Update radios
* Improve unsupported device handling
This commit is contained in:
Tim Wilkinson 2023-04-22 06:24:20 -07:00 committed by GitHub
parent 291ba2d012
commit 8711afa9ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 216 additions and 967 deletions

File diff suppressed because it is too large Load Diff

View File

@ -42,8 +42,6 @@ local hardware = {}
local radio_json = nil local radio_json = nil
local board_json = nil local board_json = nil
local rf_channel_map = nil
function hardware.get_board() function hardware.get_board()
if not board_json then if not board_json then
local f = io.open("/etc/board.json") local f = io.open("/etc/board.json")
@ -65,6 +63,9 @@ function hardware.get_radio()
local radios = json.parse(f:read("*a")) local radios = json.parse(f:read("*a"))
f:close() f:close()
radio_json = radios[hardware.get_board_id()] radio_json = radios[hardware.get_board_id()]
if radio_json and not radio_json.name then
radio_json.name = hardware.get_board_id()
end
end end
return radio_json return radio_json
end end
@ -239,136 +240,67 @@ function hardware.has_usb()
return false return false
end end
function hardware.get_rfband() function hardware.get_rfbandwidths(wifiintf)
local radio = hardware.get_radio() return { 5, 10, 20 }
if radio then
return radio.rfband
else
return nil
end
end end
function hardware.get_rfbandwidths() function hardware.get_default_channel(wifiintf)
local radio = hardware.get_radio() for _, channel in ipairs(hardware.get_rfchannels(wifiintf))
if radio.rfbandwidths then
return radio.rfbandwidths
else
return { 5, 10, 20 }
end
end
function hardware.get_default_channel()
local radio = hardware.get_radio()
if radio.rfband == "900" then
return { channel = 5, bandwidth = 5 }
end
local w = {}
for _, width in ipairs(hardware.get_rfbandwidths())
do do
w[width] = true if channel.frequency == 912 then
end return { channel = 5, bandwidth = 5 }
local width = w[10] and 10 or w[5] and 5 or 20 end
if radio.rfband == "2400" then if channel.frequency == 2397 then
local c = {} return { channel = -2, bandwidth = 10 }
for _, chan in ipairs(hardware.get_rfchannels()) end
do if channel.frequency == 2412 then
c[chan.number] = chan return { channel = 1, bandwidth = 10 }
end
if channel.frequency == 3420 then
return { channel = 84, bandwidth = 10 }
end
if channel.frequency == 5745 then
return { channel = 149, bandwidth = 10 }
end end
local chan = c[-2] and -2 or 1
return { channel = chan, bandwidth = width }
elseif radio.rfband == "3400" then
return { channel = 84, bandwidth = width }
elseif radio.rfband == "5800ubntus" then
return { channel = 149, bandwidth = width }
else
return nil
end end
return nil
end end
function hardware.get_rfchannels(wifiintf) function hardware.get_rfchannels(wifiintf)
if not rf_channel_map then
rf_channel_map = {
["900"] = {},
["2400"] = {},
["3400"] = {},
["5500"] = {},
["5800ubntus"] = {}
}
for i = 4,7
do
rf_channel_map["900"][i - 3] = { label = i .. " (" .. (887 + i * 5) .. ")", number = i, frequency = 887 + i * 5 }
end
for i = -4,11
do
rf_channel_map["2400"][i + (i <= 0 and 5 or 4)] = { label = i .. " (" .. (2407 + i * 5) .. ")", number = i, frequency = 2407 + i * 5 }
end
for i = 76,99
do
rf_channel_map["3400"][i - 75] = { label = i .. " (" .. (3000 + i * 5) .. ")", number = i, frequency = 3000 + i * 5 }
end
for i = 36,64,4
do
rf_channel_map["5500"][(i - 32) / 4] = { label = i .. " (" .. (5000 + i * 5) .. ")", number = i, frequency = 5000 + i * 5 }
end
for i = 100,140,4
do
rf_channel_map["5500"][(i - 64) / 4] = { label = i .. " (" .. (5000 + i * 5) .. ")", number = i, frequency = 5000 + i * 5 }
end
for i = 149,165,4
do
rf_channel_map["5500"][(i - 69) / 4] = { label = i .. " (" .. (5000 + i * 5) .. ")", number = i, frequency = 5000 + i * 5 }
end
for i = 131,184
do
rf_channel_map["5800ubntus"][i - 130] = { label = i .. " (" .. (5000 + i * 5) .. ")", number = i, frequency = 5000 + i * 5 }
end
end
local channels = {} local channels = {}
local rfband = hardware.get_rfband() local f = io.popen("iwinfo " .. wifiintf .. " freqlist")
if rfband and rf_channel_map[rfband] then if f then
channels = rf_channel_map[rfband] local freq_adjust = 0
else if wifiintf == "wlan0" then
local f = io.popen("iwinfo " .. wifiintf .. " freqlist") local radio = hardware.get_radio()
if f then if radio then
for line in f:lines() if radio.name:match("M9") then
do freq_adjust = -1520;
local freq, num = line:match("(%d+%.%d+) GHz %(Channel (%d+)%)") elseif radio.name:match("M3") then
if freq and not line:match("restricted") then freq_adjust = -2000;
freq = freq:gsub("%.", "")
num = num:gsub("^0+", "")
channels[#channels + 1] = {
label = num .. " (" .. freq .. ")",
number = tonumber(num),
frequency = freq
}
end end
end end
f:close()
end end
end for line in f:lines()
local radio = hardware.get_radio()
if radio.rfblocked then
for _, chan in ipairs(radio.rfblocked)
do do
for idx, channel in ipairs(channels) local freq, num = line:match("(%d+%.%d+) GHz %(Channel (%-?%d+)%)")
do if freq and not line:match("restricted") and not line:match("disabled") then
if channel.number == chan then freq = tonumber("" .. freq:gsub("%.", "")) + freq_adjust
table.remove(channels, idx) num = tonumber("" .. num:gsub("^0+", ""))
break channels[#channels + 1] = {
end label = num .. " (" .. freq .. ")",
number = num,
frequency = freq
}
end end
end end
f:close()
end end
return channels return channels
end end
function hardware.supported() function hardware.supported()
local radio = hardware.get_radio() return hardware.get_radio() and true or false
if radio then
return tonumber(radio.supported)
else
return 0
end
end end
function hardware.get_interface_ip4(intf) function hardware.get_interface_ip4(intf)

View File

@ -69,13 +69,8 @@ end
function html.alert_banner() function html.alert_banner()
html.print("<div class=\"TopBanner\">") html.print("<div class=\"TopBanner\">")
html.print("<div class=\"LogoDiv\"><a href=\"http://localnode.local.mesh:8080\" title=\"Go to localnode\"><img src=\"/AREDN.png\" class=\"AREDNLogo\"></img></a></div>") html.print("<div class=\"LogoDiv\"><a href=\"http://localnode.local.mesh:8080\" title=\"Go to localnode\"><img src=\"/AREDN.png\" class=\"AREDNLogo\"></img></a></div>")
local supported = aredn.hardware.supported() if not aredn.hardware.supported() then
if supported == 0 then html.print("<center><div style=\"padding:5px;background-color:#FF4719;color:black;border:1px solid #ccc;width:600px;\"><a href=\"/cgi-bin/sysinfo\">!!!! UNSUPPORTED DEVICE !!!!</a></div></center>")
html.print("<div style=\"padding:5px;background-color:#FF4719;color:black;border:1px solid #ccc;width:600px;\"><a href=\"/cgi-bin/sysinfo\">!!!! UNSUPPORTED DEVICE !!!!</a></div>")
elseif supported == -2 then
html.print("<div style=\"padding:5px;background-color:yellow;color:black;border:1px solid #ccc;width:600px;\"><a href=\"/cgi-bin/sysinfo\"> !!!! THIS DEVICE IS STILL BEING TESTED !!!!</a></div>")
elseif supported ~= 1 then
html.print("<div style=\"padding:5px;background-color:yellow;color:black;border:1px solid #ccc;width:600px;\"><a href=\"/cgi-bin/sysinfo\">!!!! UNTESTED HARDWARE !!!!</a></div>")
end end
html.print("</div>") html.print("</div>")
end end

View File

@ -129,21 +129,6 @@ function out(str)
output[#output + 1] = str output[#output + 1] = str
end end
function is_channel_valid(channel)
local list = aredn.hardware.get_rfchannels(aredn.hardware.get_iface_name("wifi"))
for _, c in ipairs(list)
do
if c.number == channel then
return true
end
end
return false
end
function is_wifi_chanbw_valid(wifi_chanbw, wifi_ssid)
return true -- always true
end
function validate_hostname(raw_name, name_type) function validate_hostname(raw_name, name_type)
local trimmed_name = raw_name:match("^%s*(.-)%s*$") local trimmed_name = raw_name:match("^%s*(.-)%s*$")
if trimmed_name == "" then if trimmed_name == "" then
@ -190,13 +175,10 @@ wan_gw = ""
passwd1 = "" passwd1 = ""
passwd2 = "" passwd2 = ""
local ctwo = { 1,2,3,4,5,6,7,8,9,10,11 }
local cfive = { 36,40,44,48,149,153,157,161,163,165,167,169,171,173,175,177 }
local wifiintf = aredn.hardware.get_iface_name("wifi") local wifiintf = aredn.hardware.get_iface_name("wifi")
local phy = iwinfo.nl80211.phyname(wifiintf) local phy = iwinfo.nl80211.phyname(wifiintf)
local phycount = tonumber(capture("ls -1d /sys/class/ieee80211/* | wc -l"):chomp()) local phycount = tonumber(capture("ls -1d /sys/class/ieee80211/* | wc -l"):chomp())
local radio_name = aredn.hardware.get_radio().name or "" local radio_name = (aredn.hardware.get_radio() or {}).name or ""
local M9model = radio_name:match("M9") local M9model = radio_name:match("M9")
local M3model = radio_name:match("M3") local M3model = radio_name:match("M3")
local M39model = M9model or M3model local M39model = M9model or M3model
@ -528,22 +510,31 @@ if parms.button_save then
end end
end end
if not validate_netmask(wifi_mask) then if wifi_enable == "1" then
err("invalid Mesh netmask") if not validate_netmask(wifi_mask) then
elseif not validate_ip_netmask(wifi_ip, wifi_mask) then err("invalid Mesh netmask")
err("invalid Mesh IP address") elseif not validate_ip_netmask(wifi_ip, wifi_mask) then
end err("invalid Mesh IP address")
end
if #wifi_ssid > 32 then if #wifi_ssid > 32 then
err("invalid Mesh RF SSID") err("invalid Mesh RF SSID")
end end
if not is_channel_valid(wifi_channel) then if wifiintf:match("^br") then
err("invalid Mesh RF channel") wifiintf = "wlan0"
end end
if not is_wifi_chanbw_valid(wifi_chanbw, wifi_ssid) then local valid = false
err("Invalid Mesh RF channel width") for _, c in ipairs(aredn.hardware.get_rfchannels(wifiintf))
wifi_chanbw = 20 do
if c.number == wifi_channel then
valid = true
break
end
end
if not valid then
err("invalid Mesh RF channel")
end
end end
local wifi_country_validated = false local wifi_country_validated = false
@ -1055,7 +1046,7 @@ html.print([[
-- reset wifi channel/bandwidth to default -- reset wifi channel/bandwidth to default
if nixio.fs.stat("/etc/config/unconfigured") or parms.button_reset then if nixio.fs.stat("/etc/config/unconfigured") or parms.button_reset then
local defaultwifi = aredn.hardware.get_default_channel() local defaultwifi = aredn.hardware.get_default_channel(wifiintf)
wifi_channel = defaultwifi.channel wifi_channel = defaultwifi.channel
wifi_chanbw = tostring(defaultwifi.bandwidth) wifi_chanbw = tostring(defaultwifi.bandwidth)
end end
@ -1087,7 +1078,7 @@ if wifi_enable == "1" then
html.print("</select>&nbsp;&nbsp;<a href='/help.html#channel' target='_blank'><img src='/qmark.png'></a></td></tr>") html.print("</select>&nbsp;&nbsp;<a href='/help.html#channel' target='_blank'><img src='/qmark.png'></a></td></tr>")
html.print("<tr><td>Channel Width</td><td><select name=wifi_chanbw>") html.print("<tr><td>Channel Width</td><td><select name=wifi_chanbw>")
for _, width in ipairs(aredn.hardware.get_rfbandwidths()) for _, width in ipairs(aredn.hardware.get_rfbandwidths(wifiintf))
do do
html.print("<option value='" .. width .. "'".. (wifi_chanbw == tostring(width) and " selected" or "") .. ">" .. width .. " MHz</option>") html.print("<option value='" .. width .. "'".. (wifi_chanbw == tostring(width) and " selected" or "") .. ">" .. width .. " MHz</option>")
end end
@ -1217,37 +1208,33 @@ if APokay and ((phycount > 1 and (wifi_enable ~= "1" or wifi3_enable ~= "1")) or
-- lan ap shows as an option -- lan ap shows as an option
-- determine hardware options and set band ahd channels accordingly -- determine hardware options and set band ahd channels accordingly
if phycount == 1 then if phycount == 1 then
local rc3 = os.execute("iw phy phy0 info | grep -v disabled | grep -q '5180 MHz' > /dev/null") chan = aredn.hardware.get_rfchannels("wlan0")
if rc3 ~= 0 then if chan[1].frequency < 3000 then
wifi2_hwmode = "11g" wifi2_hwmode = "11g"
if wifi2_channel > 14 then if wifi2_channel > 14 then
wifi2_channel = 1 wifi2_channel = 1
end end
chan = ctwo
else else
wifi2_hwmode = "11a" wifi2_hwmode = "11a"
if wifi2_channel < 36 then if wifi2_channel < 36 then
wifi2_channel = 36 wifi2_channel = 36
end end
chan = cfive
end end
else else
-- 2 band device -- 2 band device
if wifi_enable == "1" then if wifi_enable == "1" then
local alt_phy = (not phy or phy == "phy0") and "phy1" or "phy0" local alt_wifi = (not phy or phy == "phy0") and "wlan1" or "wlan0"
local rc3 = os.execute("iw " .. alt_phy .. " info | grep -v disabled | grep -q '5180 MHz' > /dev/null") chan = aredn.hardware.get_rfchannels(alt_wifi)
if rc3 ~= 0 then if chan[1].frequency < 3000 then
wifi2_hwmode = "11g" wifi2_hwmode = "11g"
if wifi2_channel > 14 then if wifi2_channel > 14 then
wifi2_channel = 1 wifi2_channel = 1
end end
chan = ctwo
else else
wifi2_hwmode = "11a" wifi2_hwmode = "11a"
if wifi2_channel < 36 then if wifi2_channel < 36 then
wifi2_channel = 36 wifi2_channel = 36
end end
chan = cfive
end end
else else
if wifi2_enable ~= "1" and wifi3_enable == "1" and wifi3_hwmode == "11a" then if wifi2_enable ~= "1" and wifi3_enable == "1" and wifi3_hwmode == "11a" then
@ -1256,16 +1243,26 @@ if APokay and ((phycount > 1 and (wifi_enable ~= "1" or wifi3_enable ~= "1")) or
if wifi2_enable ~= "1" and wifi3_enable == "1" and wifi3_hwmode == "11g" then if wifi2_enable ~= "1" and wifi3_enable == "1" and wifi3_hwmode == "11g" then
wifi2_hwmode = "11a" wifi2_hwmode = "11a"
end end
local chan0 = aredn.hardware.get_rfchannels("wlan0")
local chan1 = aredn.hardware.get_rfchannels("wlan1")
if wifi2_hwmode == "11a" then if wifi2_hwmode == "11a" then
if chan0[1].frequency > 3000 then
chan = chan0
else
chan = chan1
end
if wifi2_channel < 36 then if wifi2_channel < 36 then
wifi2_channel = 36 wifi2_channel = 36
end end
chan = cfive
else else
if chan0[1].frequency < 3000 then
chan = chan0
else
chan = chan1
end
if wifi2_channel > 14 then if wifi2_channel > 14 then
wifi2_channel = 1 wifi2_channel = 1
end end
chan = ctwo
end end
end end
end end
@ -1285,25 +1282,27 @@ if APokay and ((phycount > 1 and (wifi_enable ~= "1" or wifi3_enable ~= "1")) or
end end
html.print("<tr><td>SSID</td><td><input type=text size=15 name=wifi2_ssid value='" .. wifi2_ssid .."'></td></tr>") html.print("<tr><td>SSID</td><td><input type=text size=15 name=wifi2_ssid value='" .. wifi2_ssid .."'></td></tr>")
html.print("<tr><td>Channel</td><td><select name=wifi2_channel>") html.print("<tr><td>Channel</td><td><select name=wifi2_channel>")
if chan == cfive then if chan[1].frequency > 3000 then
html.print("<optgroup label='Standard Channels'>") html.print("<optgroup label='Standard Channels'>")
for _, chnum in ipairs(chan) do for _, ch in ipairs(chan)
if chnum < 163 or chnum == 165 then do
html.print("<option value='" .. chnum .. "'" .. (wifi2_channel == chnum and " selected" or "") .. ">" .. chnum .. "</option>") if ch.number < 163 or ch.number == 165 then
html.print("<option value='" .. ch.number .. "'" .. (wifi2_channel == ch.number and " selected" or "") .. ">" .. ch.number .. "</option>")
end end
end end
html.print("</optgroup>") html.print("</optgroup>")
html.print("<optgroup label='Extended Channels'>") html.print("<optgroup label='Extended Channels'>")
for _, chnum in ipairs(chan) do for _, ch in ipairs(chan)
if chnum == 163 or chnum > 165 then do
html.print("<option value='" .. chnum .. "'" .. (wifi2_channel == chnum and " selected" or "") .. ">" .. chnum .. "</option>") if ch.number == 163 or ch.number > 165 then
html.print("<option value='" .. ch.number .. "'" .. (wifi2_channel == ch.number and " selected" or "") .. ">" .. ch.number .. "</option>")
end end
end end
html.print("</optgroup>") html.print("</optgroup>")
else else
for i = 1,#chan for _, ch in ipairs(chan)
do do
html.print("<option value='" .. chan[i] .. "'" .. (wifi2_channel == chan[i] and " selected" or "") .. ">" .. chan[i] .. "</option>") html.print("<option value='" ..ch.number .. "'" .. (wifi2_channel == ch.number and " selected" or "") .. ">" .. ch.number .. "</option>")
end end
end end
html.print("</select></td></tr>") html.print("</select></td></tr>")

View File

@ -53,14 +53,9 @@ html.print(" node: " .. node)
html.print("model: " .. aredn.hardware.get_board_id()) html.print("model: " .. aredn.hardware.get_board_id())
html.print("") html.print("")
if aredn.hardware.supported() ~= 1 then if not aredn.hardware.supported() then
html.print("<font color=\"red\">!!!! UNSUPPORTED DEVICE !!!!</font>") html.print("<font color=\"red\">!!!! UNSUPPORTED DEVICE !!!!</font>")
html.print("boardid: " .. aredn.hardware.get_board_id()) html.print("boardid: " .. aredn.hardware.get_board_id())
if aredn.hardware.supported() == 0 then
html.print("<font color=\"red\">Device HAS BEEN TESTED AS UNSUPPORTED</font>")
else
html.print("<font color=\"red\">Device has not been tested. Please file a ticket with your experiences.</font>")
end
html.print("") html.print("")
end end