fix: non-disruptive env check — drop wifi reload + misleading hop warning

- STA uplink disable now uses uci commit + ip link set wlan0 down instead of
  wifi reload, so the env check never bounces radios/APs/drops monitors
- Removed the wlan0mon 'hop is off' warning: field-verified hop=0 is normal
  (wlan1mon also reports 0 while scanning both bands); the STA/AP pinning
  checks are the real signals
- recon/status drops wlan0_hopping; UI keeps wlan0_sta + wlan0_pinned pills
This commit is contained in:
2026-08-19 10:55:26 -05:00
parent 5a72566381
commit 6e3968c19a
3 changed files with 11 additions and 77 deletions
@@ -1360,7 +1360,6 @@ def h_recon_status(ctx):
'hopper_online': _hopper_online(),
'wlan0_pinned': _wlan0_pinned(),
'wlan0_sta': _sta_uplink_enabled(),
'wlan0_hopping': _wlan0_hopping(),
'history_reset': _recon_history_reset()}
@@ -3727,43 +3726,14 @@ def _sta_uplink_enabled():
def _disable_sta_uplink():
"""Disable the dummy_radio0 STA without bouncing the radios. The UCI flag
keeps it off across reboots/wifi reloads; taking wlan0 down immediately
frees phy0's channel for wlan0mon. Never runs `wifi reload` here — that
tears down live APs and drops the monitors mid-assessment."""
device_run(['uci', 'set', 'wireless.dummy_radio0.disabled=1'])
device_run(['uci', 'commit', 'wireless'])
device_run(['wifi', 'reload'], timeout=30)
def _pineap_interfaces():
"""Runtime pineapd interface table from ``_pineap INTERFACE LIST``:
{name: {'channels': int, 'bands': str, 'hop': str, 'pkts': int}}."""
rc, out, err = _pineap('INTERFACE', 'LIST', timeout=15)
if rc != 0:
return {}
result = {}
for line in (out or '').splitlines():
parts = line.split()
if len(parts) < 7 or not parts[0].startswith('wlan'):
continue
result[parts[0]] = {
'channels': int(parts[1]) if parts[1].isdigit() else None,
'bands': parts[2],
'type': parts[3],
'hop': parts[4],
'chan': parts[5],
'pkts': int(parts[6]) if parts[6].isdigit() else None,
}
return result
def _wlan0_hopping():
"""Whether pineapd is actually hopping wlan0mon at runtime. The band UCI
config can be correct while runtime hopping is off, which starves 2.4GHz
recon results entirely."""
ifaces = _pineap_interfaces()
mon = ifaces.get('wlan0mon')
if not mon:
return None
hop = mon.get('hop')
return bool(hop) and hop not in ('0', '', 'none', 'false')
for iface in ('wlan0',):
rc, out, err = device_run(['ip', 'link', 'set', iface, 'down'], timeout=10)
def env_check():
@@ -3831,16 +3801,6 @@ def env_check():
else:
_env_step(report, 'pass', 'no radio0 AP pins wlan0mon')
hopping = _wlan0_hopping()
if hopping is False:
_env_step(report, 'warn', '2.4GHz recon starved: wlan0mon hopping is off at '
'runtime (INTERFACE LIST hop=0)')
elif hopping is None:
_env_step(report, 'warn', 'could not read pineapd interface state '
'(INTERFACE LIST failed)')
else:
_env_step(report, 'pass', 'wlan0mon hopping on (2.4GHz scanning active)')
ENV_CHECK_STATE['report'] = report
ENV_CHECK_STATE['overall'] = _env_overall(report)
ENV_CHECK_STATE['updated'] = time.time()