Skip to content

Commit 6709f35

Browse files
authored
[fix/change] Skip wireless section if wifi channel not available #113
Fixes #113
1 parent 45f50ac commit 6709f35

8 files changed

Lines changed: 207 additions & 61 deletions

File tree

openwisp-monitoring/files/lib/openwisp-monitoring/utils.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ end
3838

3939
function utils.is_excluded(name) return name == 'lo' end
4040

41+
function utils.is_empty(data) return data == nil or data == false or data == '' end
42+
4143
return utils

openwisp-monitoring/files/lib/openwisp-monitoring/wifi.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ wifi.iwinfo_modes = {
99
}
1010

1111
function wifi.needs_inversion(interface)
12-
return interface.type == 'wireless' and interface.wireless.mode == 'access_point'
12+
if interface.wireless then
13+
return interface.type == 'wireless' and interface.wireless.mode == 'access_point'
14+
end
1315
end
1416

1517
function wifi.invert_rx_tx(interface)

openwisp-monitoring/files/sbin/netjson-monitoring.lua

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,43 +70,51 @@ local host_interfaces = {}
7070
local dns_servers = {}
7171
local dns_search = {}
7272

73+
local function get_wireless_netjson_interface(radio, name, iwinfo)
74+
local clients = nil
75+
local is_mesh = false
76+
local htmode = radio.config.htmode
77+
local netjson_interface = {
78+
name = name,
79+
type = 'wireless',
80+
}
81+
-- if channel is missing the WiFi interface is not fully up
82+
-- and hence we avoid including its info because it will be rejected
83+
if monitoring.utils.is_empty(iwinfo.channel) == false then
84+
netjson_interface.wireless = {
85+
ssid = iwinfo.ssid,
86+
mode = monitoring.wifi.iwinfo_modes[iwinfo.mode] or iwinfo.mode,
87+
channel = iwinfo.channel,
88+
frequency = iwinfo.frequency,
89+
tx_power = iwinfo.txpower,
90+
signal = iwinfo.signal,
91+
noise = iwinfo.noise,
92+
country = iwinfo.country,
93+
htmode = htmode
94+
}
95+
if iwinfo.mode == 'Ad-Hoc' or iwinfo.mode == 'Mesh Point' then
96+
clients = ubus:call('iwinfo', 'assoclist', {device = name}).results
97+
is_mesh = true
98+
else
99+
local hostapd_output = ubus:call('hostapd.' .. name, 'get_clients', {})
100+
if hostapd_output then clients = hostapd_output.clients end
101+
end
102+
if not monitoring.utils.is_table_empty(clients) then
103+
netjson_interface.wireless.clients = monitoring.wifi.netjson_clients(clients,
104+
is_mesh)
105+
end
106+
end
107+
return netjson_interface
108+
end
109+
73110
-- collect relevant wireless interface stats
74111
-- (traffic and connected clients)
75112
for _, radio in pairs(wireless_status) do
76113
for _, interface in ipairs(radio.interfaces) do
77114
local name = interface.ifname
78-
local is_mesh = false
79-
local clients = nil
80-
local htmode = radio.config.htmode
81115
if name and not monitoring.utils.is_excluded(name) then
82116
local iwinfo = ubus:call('iwinfo', 'info', {device = name})
83-
local netjson_interface = {
84-
name = name,
85-
type = 'wireless',
86-
wireless = {
87-
ssid = iwinfo.ssid,
88-
mode = monitoring.wifi.iwinfo_modes[iwinfo.mode] or iwinfo.mode,
89-
channel = iwinfo.channel,
90-
frequency = iwinfo.frequency,
91-
tx_power = iwinfo.txpower,
92-
signal = iwinfo.signal,
93-
noise = iwinfo.noise,
94-
country = iwinfo.country,
95-
htmode = htmode
96-
}
97-
}
98-
if iwinfo.mode == 'Ad-Hoc' or iwinfo.mode == 'Mesh Point' then
99-
clients = ubus:call('iwinfo', 'assoclist', {device = name}).results
100-
is_mesh = true
101-
else
102-
local hostapd_output = ubus:call('hostapd.' .. name, 'get_clients', {})
103-
if hostapd_output then clients = hostapd_output.clients end
104-
end
105-
if not monitoring.utils.is_table_empty(clients) then
106-
netjson_interface.wireless.clients =
107-
monitoring.wifi.netjson_clients(clients, is_mesh)
108-
end
109-
wireless_interfaces[name] = netjson_interface
117+
wireless_interfaces[name] = get_wireless_netjson_interface(radio, name, iwinfo)
110118
end
111119
end
112120
end

openwisp-monitoring/tests/test_files/interface_data.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,9 @@ test_data.br_lan_interface = {
292292
proto = "dhcp"
293293
}
294294
},
295-
bridge_members = {"lan1", "lan2", "mesh0", "mesh1", "wan", "wlan0", "wlan1"},
295+
bridge_members = {
296+
"lan1", "lan2", "mesh0", "mesh1", "wan", "wlan0", "wlan1", "wlan2"
297+
},
296298
mac = "00:00:00:00:00:00",
297299
mtu = 1500,
298300
multicast = true,

openwisp-monitoring/tests/test_files/network_data.lua

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,56 @@ test_data.wireless = {
261261
rx_fifo_errors = 0,
262262
tx_carrier_errors = 0
263263
}
264+
},
265+
wlan2 = {
266+
external = true,
267+
present = true,
268+
type = "Network device",
269+
up = true,
270+
carrier = true,
271+
mtu = 1500,
272+
mtu6 = 1500,
273+
macaddr = "00:00:00:00:00:00",
274+
txqueuelen = 1000,
275+
ipv6 = false,
276+
promisc = false,
277+
rpfilter = 0,
278+
acceptlocal = false,
279+
igmpversion = 0,
280+
mldversion = 0,
281+
neigh4reachabletime = 30000,
282+
neigh6reachabletime = 30000,
283+
neigh4gcstaletime = 60,
284+
neigh6gcstaletime = 60,
285+
neigh4locktime = 100,
286+
dadtransmits = 1,
287+
multicast = true,
288+
sendredirects = true,
289+
statistics = {
290+
collisions = 0,
291+
rx_frame_errors = 0,
292+
tx_compressed = 0,
293+
multicast = 0,
294+
rx_length_errors = 0,
295+
tx_dropped = 0,
296+
rx_bytes = 25969,
297+
rx_missed_errors = 0,
298+
tx_errors = 0,
299+
rx_compressed = 0,
300+
rx_over_errors = 0,
301+
tx_fifo_errors = 0,
302+
rx_crc_errors = 0,
303+
rx_packets = 0,
304+
tx_heartbeat_errors = 0,
305+
rx_dropped = 0,
306+
tx_aborted_errors = 0,
307+
tx_packets = 2367519,
308+
rx_errors = 0,
309+
tx_bytes = 531596852,
310+
tx_window_errors = 0,
311+
rx_fifo_errors = 0,
312+
tx_carrier_errors = 0
313+
}
264314
}
265315
}
266316

@@ -271,7 +321,9 @@ test_data.devices = {
271321
type = "bridge",
272322
up = true,
273323
carrier = true,
274-
["bridge-members"] = {"lan1", "lan2", "mesh0", "mesh1", "wan", "wlan0", "wlan1"},
324+
["bridge-members"] = {
325+
"lan1", "lan2", "mesh0", "mesh1", "wan", "wlan0", "wlan1", "wlan2"
326+
},
275327
mtu = 1500,
276328
mtu6 = 1500,
277329
macaddr = "00:00:00:00:00:00",

openwisp-monitoring/tests/test_files/wireless_data.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,23 @@ test_data.wireless_status = {
9494
},
9595
vlans = {},
9696
stations = {}
97+
}, {
98+
section = "wifi_wlan2",
99+
ifname = "wlan2",
100+
config = {
101+
ifname = "wlan2",
102+
encryption = "psk2",
103+
key = "password",
104+
ssid = "ssid",
105+
ieee80211r = true,
106+
ft_over_ds = true,
107+
ft_psk_generate_local = true,
108+
rsn_preauth = true,
109+
mode = "ap",
110+
network = {"lan"}
111+
},
112+
vlans = {},
113+
stations = {}
97114
}
98115
}
99116
}
@@ -156,6 +173,18 @@ test_data.wlan1_iwinfo = {
156173
signal = -33
157174
}
158175

176+
test_data.wlan2_iwinfo = {
177+
phy = "phy2",
178+
ssid = "OpenWRT2",
179+
mode = "Client",
180+
channel = nil,
181+
txpower = 20,
182+
country = "00",
183+
noise = 0,
184+
frequency = 4472,
185+
signal = -32
186+
}
187+
159188
test_data.mesh0_iwinfo = {
160189
phy = "phy0",
161190
ssid = "meshID",
@@ -416,4 +445,24 @@ test_data.wlan1_interface = {
416445
}
417446
}
418447

448+
test_data.wlan2_interface = {
449+
mac = "00:00:00:00:00:00",
450+
mtu = 1500,
451+
multicast = true,
452+
name = "wlan2",
453+
txqueuelen = 1000,
454+
type = "wireless",
455+
up = true,
456+
wireless = {
457+
channel = nil,
458+
country = "00",
459+
frequency = 4472,
460+
mode = "station",
461+
noise = 0,
462+
signal = -32,
463+
ssid = "OpenWRT2",
464+
tx_power = 20
465+
}
466+
}
467+
419468
return test_data

openwisp-monitoring/tests/test_utils.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,13 @@ function TestUtils.testIsExcluded()
6565
luaunit.assertFalse(utils.is_excluded('wlo1'))
6666
end
6767

68+
function TestUtils.testIsEmpty()
69+
luaunit.assertTrue(utils.is_empty(''))
70+
luaunit.assertTrue(utils.is_empty(nil))
71+
luaunit.assertTrue(utils.is_empty(false))
72+
luaunit.assertFalse(utils.is_empty('-12'))
73+
luaunit.assertFalse(utils.is_empty(12))
74+
luaunit.assertFalse(utils.is_empty(-12))
75+
end
76+
6877
os.exit(luaunit.LuaUnit.run())

openwisp-monitoring/tests/test_wifi.lua

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ TestNetJSON = {
3434
return wifi_data.wlan0_iwinfo
3535
elseif arg[4].device == "wlan1" then
3636
return wifi_data.wlan1_iwinfo
37+
elseif arg[4].device == "wlan2" then
38+
return wifi_data.wlan2_iwinfo
3739
elseif arg[4].device == "mesh0" then
3840
return wifi_data.mesh0_iwinfo
3941
elseif arg[4].device == "mesh1" then
@@ -103,48 +105,68 @@ end
103105
function TestNetJSON.test_wifi_interfaces()
104106
local netjson_string = require('netjson-monitoring')
105107
local netjson = cjson.decode(netjson_string)
106-
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["signal"], -67)
107-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["signal"], -76)
108-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["ssid"], "meshID")
109-
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["ssid"], "meshID")
110-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["tx_power"], 20)
111-
luaunit.assertEquals(netjson["interfaces"][3]["wireless"]["tx_power"], 20)
108+
luaunit.assertEquals(netjson["interfaces"][5]["wireless"]["signal"], -67)
109+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["signal"], -76)
110+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["ssid"], "meshID")
111+
luaunit.assertEquals(netjson["interfaces"][5]["wireless"]["ssid"], "meshID")
112+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["tx_power"], 20)
112113
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["tx_power"], 20)
113114
luaunit.assertEquals(netjson["interfaces"][5]["wireless"]["tx_power"], 20)
114-
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["clients"][1]["vht"], true)
115-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["clients"][1]["vht"], false)
116-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["frequency"], 5200)
117-
luaunit.assertEquals(netjson["interfaces"][3]["wireless"]["mode"], "access_point")
115+
luaunit.assertEquals(netjson["interfaces"][6]["wireless"]["tx_power"], 20)
116+
luaunit.assertEquals(netjson["interfaces"][5]["wireless"]["clients"][1]["vht"], true)
117+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["clients"][1]["vht"],
118+
false)
119+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["frequency"], 5200)
120+
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["mode"], "access_point")
118121
end
119122

120123
function TestNetJSON.test_wifi_interfaces_stats_include()
121124
local netjson_file = assert(loadfile('../files/sbin/netjson-monitoring.lua'))
122125
local netjson = cjson.decode(netjson_file('wlan0 wlan1 mesh1'))
123-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["channel"], 40)
124-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["mode"], "802.11s")
125-
luaunit.assertEquals(netjson["interfaces"][5]["statistics"]["rx_packets"], 198)
126-
luaunit.assertEquals(netjson["interfaces"][3]["statistics"]["rx_packets"], 2367515)
127-
luaunit.assertEquals(netjson["interfaces"][5]["statistics"]["rx_bytes"], 25967)
128-
luaunit.assertEquals(netjson["interfaces"][5]["statistics"]["tx_bytes"], 531641723)
129-
luaunit.assertEquals(netjson["interfaces"][1]["statistics"]["tx_bytes"],
126+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["channel"], 40)
127+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["mode"], "802.11s")
128+
luaunit.assertEquals(netjson["interfaces"][6]["statistics"]["rx_packets"], 198)
129+
luaunit.assertEquals(netjson["interfaces"][4]["statistics"]["rx_packets"], 2367515)
130+
luaunit.assertEquals(netjson["interfaces"][6]["statistics"]["rx_bytes"], 25967)
131+
luaunit.assertEquals(netjson["interfaces"][6]["statistics"]["tx_bytes"], 531641723)
132+
luaunit.assertEquals(netjson["interfaces"][2]["statistics"]["tx_bytes"],
130133
151599685066)
131-
luaunit.assertEquals(netjson["interfaces"][5]["statistics"]["tx_packets"], 2367747)
132-
luaunit.assertEquals(netjson["interfaces"][1]["statistics"]["tx_errors"], 0)
133-
luaunit.assertEquals(netjson["interfaces"][3]["statistics"]["tx_errors"], 0)
134-
luaunit.assertEquals(netjson["interfaces"][5]["statistics"]["tx_errors"], 0)
134+
luaunit.assertEquals(netjson["interfaces"][6]["statistics"]["tx_packets"], 2367747)
135+
luaunit.assertEquals(netjson["interfaces"][2]["statistics"]["tx_errors"], 0)
136+
luaunit.assertEquals(netjson["interfaces"][4]["statistics"]["tx_errors"], 0)
137+
luaunit.assertEquals(netjson["interfaces"][6]["statistics"]["tx_errors"], 0)
135138
end
136139

137140
function TestNetJSON.test_wifi_interfaces_stats_include_htmode()
138141
local netjson_file = assert(loadfile('../files/sbin/netjson-monitoring.lua'))
139142
local netjson = cjson.decode(netjson_file('wlan0 wlan1 mesh1'))
140-
luaunit.assertEquals(netjson["interfaces"][1]["name"], "mesh1")
141-
luaunit.assertEquals(netjson["interfaces"][1]["wireless"]["htmode"], "VHT80")
142-
luaunit.assertEquals(netjson["interfaces"][3]["name"], "wlan1")
143-
luaunit.assertEquals(netjson["interfaces"][3]["wireless"]["htmode"], "VHT80")
144-
luaunit.assertEquals(netjson["interfaces"][4]["name"], "mesh0")
145-
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["htmode"], "HT20")
146-
luaunit.assertEquals(netjson["interfaces"][5]["name"], "wlan0")
143+
luaunit.assertEquals(netjson["interfaces"][1]["name"], "wlan2")
144+
luaunit.assertEquals(netjson["interfaces"][2]["name"], "mesh1")
145+
luaunit.assertEquals(netjson["interfaces"][2]["wireless"]["htmode"], "VHT80")
146+
luaunit.assertEquals(netjson["interfaces"][4]["name"], "wlan1")
147+
luaunit.assertEquals(netjson["interfaces"][4]["wireless"]["htmode"], "VHT80")
148+
luaunit.assertEquals(netjson["interfaces"][5]["name"], "mesh0")
147149
luaunit.assertEquals(netjson["interfaces"][5]["wireless"]["htmode"], "HT20")
150+
luaunit.assertEquals(netjson["interfaces"][6]["name"], "wlan0")
151+
luaunit.assertEquals(netjson["interfaces"][6]["wireless"]["htmode"], "HT20")
148152
end
149153

154+
function TestNetJSON.test_wifi_interfaces_when_iwinfo_channel_empty()
155+
local netjson_file = assert(loadfile('../files/sbin/netjson-monitoring.lua'))
156+
local netjson = cjson.decode(netjson_file('wlan0 wlan1 wlan2 mesh1'))
157+
-- make sure the correct `name` and `type` are present in the netjson
158+
luaunit.assertEquals(netjson["interfaces"][1]["name"], "wlan2")
159+
luaunit.assertEquals(netjson["interfaces"][1]["type"], "wireless")
160+
-- the `wireless` key should be missing when "iwinfo.channel" is `nil`
161+
luaunit.assertNil(netjson["interfaces"][1]["wireless"])
162+
luaunit.assertEquals(netjson["interfaces"][2]["name"], "mesh1")
163+
luaunit.assertIsTable(netjson["interfaces"][2]["wireless"])
164+
luaunit.assertEquals(netjson["interfaces"][3]["name"], "wan")
165+
luaunit.assertEquals(netjson["interfaces"][4]["name"], "wlan1")
166+
luaunit.assertIsTable(netjson["interfaces"][4]["wireless"])
167+
luaunit.assertEquals(netjson["interfaces"][5]["name"], "mesh0")
168+
luaunit.assertIsTable(netjson["interfaces"][5]["wireless"])
169+
luaunit.assertEquals(netjson["interfaces"][6]["name"], "wlan0")
170+
luaunit.assertIsTable(netjson["interfaces"][6]["wireless"])
171+
end
150172
os.exit(luaunit.LuaUnit.run())

0 commit comments

Comments
 (0)