luci-mod-network: wireless: add WPA3-Personal Compatibility Mode

Expose the sae-compat encryption mode (WPA3-Personal Compatibility Mode)
in the wireless security settings. It advertises WPA2-PSK in the base
RSNE while offering SAE through RSN Override elements, so that both
legacy WPA2 and modern WPA3 clients can connect to a single SSID.

The mode relies on RSN overriding, which is an access-point feature, so
it is offered for AP mode only. It gets the passphrase field and, like
the other WPA2/WPA3 modes, the 802.11r, KRACK-countermeasure and WPS
options.

Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/luci/pull/8790
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Hauke Mehrtens
2026-07-04 01:50:45 +02:00
parent 5b95f7c901
commit 7af3cf4f00
@@ -1375,6 +1375,10 @@ return view.extend({
crypto_modes.push(['sae-mixed', 'WPA2-PSK/WPA3-SAE Mixed Mode', 30]);
}
// WPA3-Personal Compatibility Mode uses RSN overriding, which is an AP-only feature
if (has_ap_sae)
crypto_modes.push(['sae-compat', 'WPA2-PSK/WPA3-SAE Compatibility Mode', 30]);
if (has_ap_wep || has_sta_wep) {
crypto_modes.push(['wep-open', _('WEP Open System'), 11]);
crypto_modes.push(['wep-shared', _('WEP Shared Key'), 10]);
@@ -1404,6 +1408,7 @@ return view.extend({
'psk-mixed': has_hostapd || _('Requires hostapd'),
'sae': has_ap_sae || _('Requires hostapd with SAE support'),
'sae-mixed': has_ap_sae || _('Requires hostapd with SAE support'),
'sae-compat': has_ap_sae || _('Requires hostapd with SAE support'),
'wpa': has_ap_eap || _('Requires hostapd with EAP support'),
'wpa2': has_ap_eap || _('Requires hostapd with EAP support'),
'wpa3': has_ap_eap192 || _('Requires hostapd with EAP Suite-B support'),
@@ -1813,6 +1818,7 @@ return view.extend({
add_dependency_permutations(o, { mode: ['sta', 'adhoc', 'mesh', 'sta-wds'], encryption: ['psk', 'psk2', 'psk+psk2', 'psk-mixed'] });
o.depends('encryption', 'sae');
o.depends('encryption', 'sae-mixed');
o.depends('encryption', 'sae-compat');
o.datatype = 'wpakey';
o.rmempty = true;
o.password = true;
@@ -1871,7 +1877,7 @@ return view.extend({
o = ss.taboption('roaming', form.Flag, 'ieee80211r', _('802.11r Fast Transition'), _('Enables fast roaming among access points that belong to the same Mobility Domain'));
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa2', 'wpa3', 'wpa3-mixed', 'wpa3-192'] });
if (has_80211r)
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk2', 'psk-mixed', 'sae', 'sae-mixed'] });
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk2', 'psk-mixed', 'sae', 'sae-mixed', 'sae-compat'] });
o.rmempty = true;
o = ss.taboption('roaming', form.Value, 'nasid', _('NAS ID'), _('Used for two different purposes: RADIUS NAS ID and 802.11r R0KH-ID. Not needed with normal WPA(2)-PSK.'));
@@ -2149,7 +2155,7 @@ return view.extend({
}
o = ss.taboption('encryption', form.Flag, 'wpa_disable_eapol_key_retries', _('Enable key reinstallation (KRACK) countermeasures'), _('Complicates key reinstallation attacks on the client side by disabling retransmission of EAPOL-Key frames that are used to install keys. This workaround might cause interoperability issues and reduced robustness of key negotiation especially in environments with heavy traffic load.'));
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk2', 'psk-mixed', 'sae', 'sae-mixed', 'wpa2', 'wpa3', 'wpa3-mixed'] });
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk2', 'psk-mixed', 'sae', 'sae-mixed', 'sae-compat', 'wpa2', 'wpa3', 'wpa3-mixed'] });
if (L.hasSystemFeature('hostapd', 'wps') && L.hasSystemFeature('wpasupplicant')) {
o = ss.taboption('encryption', form.Flag, 'wps_pushbutton', _('Enable WPS pushbutton, requires WPA(2)-PSK/WPA3-SAE'));
@@ -2161,6 +2167,7 @@ return view.extend({
o.depends('encryption', 'psk-mixed');
o.depends('encryption', 'sae');
o.depends('encryption', 'sae-mixed');
o.depends('encryption', 'sae-compat');
}
}
}