feat(reliability): phy1 RF role manager with uplink-on-radio1
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"""Mark VIII RF role manager: radio1/phy1 is shared between an uplink STA
|
||||
(``wlan1up``) and attack work, so the roles are made mutually exclusive.
|
||||
Uplink pauses channel hopping; attack/idle resumes it."""
|
||||
ROLE_KEY = 'mk8.rfplan.role'
|
||||
IFACE = 'wlan1up'
|
||||
|
||||
|
||||
def current_role():
|
||||
from server import _uci_values
|
||||
cfg = _uci_values('wireless.%s' % IFACE) or {}
|
||||
if cfg.get('disabled') != '1' and cfg.get('mode') == 'sta':
|
||||
return 'uplink'
|
||||
return 'idle'
|
||||
|
||||
|
||||
def associated():
|
||||
"""BSSID of the uplink AP when wlan1up is associated, else None."""
|
||||
from server import device_run
|
||||
rc, out, err = device_run(['iw', 'dev', IFACE, 'link'], timeout=10)
|
||||
if rc != 0 or 'Connected' not in (out or ''):
|
||||
return None
|
||||
for line in (out or '').splitlines():
|
||||
line = line.strip()
|
||||
if line.startswith('Connected to '):
|
||||
return line.split()[2]
|
||||
return None
|
||||
|
||||
|
||||
def hop_paused():
|
||||
from server import _read_hop
|
||||
return _read_hop() == '0'
|
||||
|
||||
|
||||
def set_role(role, ssid=None, psk=None):
|
||||
from server import device_run, _pause_hop, _resume_hop
|
||||
if role not in ('uplink', 'attack', 'idle'):
|
||||
return {'ok': False, 'error': 'role must be uplink, attack or idle'}
|
||||
if role == 'uplink':
|
||||
if not ssid:
|
||||
return {'ok': False, 'error': 'ssid required'}
|
||||
cmds = [
|
||||
['uci', 'set', 'wireless.wlan1up=wifi-iface'],
|
||||
['uci', 'set', 'wireless.wlan1up.device=radio1'],
|
||||
['uci', 'set', 'wireless.wlan1up.mode=sta'],
|
||||
['uci', 'set', 'wireless.wlan1up.network=cli'],
|
||||
['uci', 'set', 'wireless.wlan1up.ssid=%s' % ssid],
|
||||
['uci', 'set', 'wireless.wlan1up.encryption=%s'
|
||||
% ('psk2' if psk else 'none')],
|
||||
['uci', 'set', 'wireless.wlan1up.disabled=0'],
|
||||
]
|
||||
if psk:
|
||||
cmds.append(['uci', 'set', 'wireless.wlan1up.key=%s' % psk])
|
||||
for c in cmds:
|
||||
device_run(c)
|
||||
# The STA rides network 'cli'; stock firmware ships it disabled but
|
||||
# present. If it is missing entirely, create a minimal DHCP interface
|
||||
# so netifd can bring wlan1up up.
|
||||
rc, _, _ = device_run(['uci', 'show', 'network.cli'])
|
||||
if rc != 0:
|
||||
device_run(['uci', 'set', 'network.cli=interface'])
|
||||
device_run(['uci', 'set', 'network.cli.proto=dhcp'])
|
||||
device_run(['uci', 'commit', 'wireless'])
|
||||
_pause_hop()
|
||||
device_run(['wifi', 'reload'], timeout=60)
|
||||
assoc = associated()
|
||||
if not assoc:
|
||||
disable_uplink()
|
||||
_resume_hop()
|
||||
return {'ok': False, 'error': 'association failed; reverted'}
|
||||
return {'ok': True, 'role': 'uplink', 'assoc': assoc}
|
||||
# attack/idle: tear down the STA so radio1 is free again.
|
||||
disable_uplink()
|
||||
_resume_hop()
|
||||
return {'ok': True, 'role': role}
|
||||
|
||||
|
||||
def disable_uplink():
|
||||
from server import device_run
|
||||
device_run(['uci', 'set', 'wireless.wlan1up.disabled=1'])
|
||||
device_run(['uci', 'commit', 'wireless'])
|
||||
|
||||
|
||||
def ensure_attack():
|
||||
"""Exclusivity hook for attack enable paths: switch uplink off first."""
|
||||
if current_role() == 'uplink':
|
||||
return set_role('attack')
|
||||
return None
|
||||
Reference in New Issue
Block a user