feat: radio1 5GHz/6GHz rogue AP via UCI with hop pause

This commit is contained in:
2026-08-17 23:28:54 -05:00
parent b2098bae7d
commit 4effc08a25
2 changed files with 182 additions and 2 deletions
@@ -1717,7 +1717,7 @@ def _apply_open_radio(openap):
daemon's iface-level channel write does not affect the actual radio, so
apply channel/country here and reload wifi when they change."""
changed = False
radio = _uci_wifi_iface('radio0')
radio = _uci_wifi_iface('radio0') or {}
for key in ('channel', 'country'):
value = openap.get(key)
if value is None:
@@ -1739,11 +1739,100 @@ def _open_channel(value):
return 1
def _read_hop():
rc, out, err = device_run(['uci', 'get', 'pineapd.wlan1mon.hop'])
return out.strip()
def _pause_hop():
if _read_hop() != '0':
device_run(['uci', 'set', 'pineapd.wlan1mon.hop=0'])
device_run(['uci', 'commit', 'pineapd'])
device_run(['/etc/init.d/pineapd', 'reload'])
def _resume_hop():
if _read_hop() == '0':
device_run(['uci', 'set', 'pineapd.wlan1mon.hop=1'])
device_run(['uci', 'commit', 'pineapd'])
device_run(['/etc/init.d/pineapd', 'reload'])
def _remove_radio1_ap():
device_run(['uci', 'delete', 'wireless.wlan1open'])
device_run(['uci', 'delete', 'wireless.wlan1wpa'])
device_run(['uci', 'set', 'wireless.radio1.channel=auto'])
device_run(['uci', 'set', 'wireless.radio1.band=5g'])
device_run(['uci', 'commit', 'wireless'])
_resume_hop()
def _apply_radio1_ap(openap, wpa):
band = None
if openap is not None:
band = channel_band(openap.get('channel'))
iface = 'wlan1open'
if wpa is not None:
band = channel_band(wpa.get('channel'))
iface = 'wlan1wpa'
if band not in (BAND_5G, BAND_6G):
raise ValueError('radio1 AP requires a 5GHz or 6GHz channel')
if band == BAND_6G and wpa is not None:
if (wpa.get('enctype') or 'psk2') not in ('sae', 'owe'):
raise ValueError('6GHz requires WPA3 (sae or owe)')
device_run(['uci', 'delete', 'wireless.wlan1open'])
device_run(['uci', 'delete', 'wireless.wlan1wpa'])
device_run(['uci', 'set', 'wireless.radio1.band=%s' % ('6g' if band == BAND_6G else '5g')])
ch = int(wpa.get('channel') if wpa is not None else openap.get('channel'))
device_run(['uci', 'set', 'wireless.radio1.channel=%d' % ch])
device_run(['uci', 'set', 'wireless.radio1.htmode=%s' % band_htmode(band)])
country = (wpa or openap or {}).get('country')
if country:
device_run(['uci', 'set', 'wireless.radio1.country=%s' % country])
cfg = wpa if wpa is not None else openap
device_run(['uci', 'set', 'wireless.%s=wifi-iface' % iface])
device_run(['uci', 'set', 'wireless.%s.device=radio1' % iface])
device_run(['uci', 'set', 'wireless.%s.mode=ap' % iface])
device_run(['uci', 'set', 'wireless.%s.ssid=%s' % (iface, cfg.get('ssid') or '')])
device_run(['uci', 'set', 'wireless.%s.hidden=%d' % (iface, 1 if cfg.get('hidden') else 0)])
device_run(['uci', 'set', 'wireless.%s.channel=%d' % (iface, int(cfg.get('channel')))])
if wpa is not None:
device_run(['uci', 'set', 'wireless.%s.encryption=%s' % (iface, wpa.get('enctype') or 'psk2')])
device_run(['uci', 'set', 'wireless.%s.key=%s' % (iface, wpa.get('passphrase') or '')])
else:
device_run(['uci', 'set', 'wireless.%s.encryption=none' % iface])
bssid = (openap or {}).get('bssid') or ''
if bssid:
device_run(['uci', 'set', 'wireless.%s.macaddr=%s' % (iface, bssid)])
device_run(['uci', 'commit', 'wireless'])
_pause_hop()
device_run(['wifi', 'reload'])
def h_pineap_wifi_set_ap(ctx):
body = ctx.body or {}
configs = []
wpa = body.get('wpa') or {}
openap = body.get('open') or {}
wpa_band = channel_band(wpa.get('channel')) if wpa.get('channel') is not None else None
open_band = channel_band(openap.get('channel')) if openap.get('channel') is not None else None
use_radio1 = wpa_band in (BAND_5G, BAND_6G) or open_band in (BAND_5G, BAND_6G)
if use_radio1:
wpa_active = bool(wpa.get('enabled', True)) and wpa.get('channel') is not None
open_active = bool(openap.get('enabled', True)) and openap.get('channel') is not None
if not (wpa_active or open_active):
_remove_radio1_ap()
device_run(['wifi', 'reload'])
return 200, {'ok': True}
try:
_apply_radio1_ap(openap if open_active else None,
wpa if wpa_active else None)
except ValueError as exc:
return 400, {'error': str(exc)}
return 200, {'ok': True}
if _uci_wifi_iface('wlan1open') or _uci_wifi_iface('wlan1wpa'):
_remove_radio1_ap()
device_run(['wifi', 'reload'])
configs = []
if wpa.get('ssid') or wpa.get('enabled') is not None:
configs.append({
'interface': 'wlan0wpa',