wifi-scripts: ucode: add gcmp256 option, default GCMP-256 per WPA3 mode

Commit 1f86f4e471 ("wifi-scripts: ucode: simplify wpa_pairwise default
selection") made HE and EHT BSSes default their pairwise cipher to
"GCMP-256 CCMP", and commit 86b9eec8f0 ("wifi-scripts: ucode: add
WPA3-Personal Compatibility Mode") always put GCMP-256 into the RSNE
Override 2 element on EHT compatibility-mode BSSes.

WPA3 Specification v3.5 only makes GCMP-256 mandatory when the BSS enables
EHT or MLO (section 2.5, item 5); for HE and below the WPA3 and Wi-Fi
Enhanced Open Deployment Guide v1.1 lists it as recommended, not required.
Advertising it by default causes interoperability problems: several
clients fail to associate when GCMP-256 is offered as a pairwise cipher
and connect again with CCMP only (Nanoleaf devices, a Motorola/Unisoc
phone, a Linux/iwd laptop).

Add a gcmp256 UCI option and, like sae_ext_key, default it on only where
GCMP-256 is both mandatory and safe: on Compatibility mode (sae-compat)
BSSes running an EHT htmode, which carry it in a separate RSNE Override 2
element that legacy clients ignore. It defaults off for WPA3-Personal
(sae) and Transition (sae-mixed) mode and on non-EHT BSSes. An explicit
'option gcmp256 0/1' overrides the default per BSS.

Both GCMP-256 pairwise defaults now key off config.gcmp256 (and, from the
earlier driver-support change, the phy actually implementing the cipher):
the sae/sae-mixed "GCMP-256 CCMP" pairwise cipher and the sae-compat RSNE
Override 2 element. The 'encryption sae+gcmp256' suffix and the wpa3-192
mode still force GCMP-256 as before.

Fixes: 1f86f4e471 ("wifi-scripts: ucode: simplify wpa_pairwise default selection")
Fixes: 86b9eec8f0 ("wifi-scripts: ucode: add WPA3-Personal Compatibility Mode")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/openwrt/pull/24041
(cherry picked from commit 5e067465ff)
Link: https://github.com/openwrt/openwrt/pull/23011
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Hauke Mehrtens
2026-07-21 22:14:30 +02:00
parent fdb8a8e5d1
commit dd8cdc8a59
2 changed files with 14 additions and 9 deletions
@@ -371,6 +371,10 @@
"gas_address3": {
"type": "string"
},
"gcmp256": {
"description": "Advertise the GCMP-256 pairwise cipher on HE/EHT BSSes (alongside CCMP for sae/sae-mixed, in the RSNE Override 2 element for sae-compat). Mandatory for EHT, recommended otherwise. Defaults off for sae and sae-mixed because some clients and chipsets misbehave when GCMP-256 is offered, and on for sae-compat BSSes using an EHT htmode (where GCMP-256 is mandatory), carried in a separate RSN Override element that legacy clients ignore. Only advertised when the driver supports the GCMP-256 cipher.",
"type": "boolean"
},
"hidden": {
"type": "alias",
"default": "ignore_broadcast_ssid"
@@ -20,15 +20,16 @@ export function parse_encryption(config, dev_config, phy_features) {
config.auth_type = encryption[0] ?? 'none';
/*
* The SAE-EXT-KEY (SAE-GDH) AKM is only mandatory for EHT/MLO and breaks
* interoperability with some clients, so only default it on where it is
* both required and safe to offer: on Compatibility mode (sae-compat)
* BSSes that run an EHT htmode, which carry it in a separate RSN Override
* element that legacy clients ignore. It stays off for WPA3-Personal (sae)
* and Transition (sae-mixed) mode and on non-EHT BSSes. An explicit
* sae_ext_key option overrides this per BSS.
* GCMP-256 and the SAE-EXT-KEY (SAE-GDH) AKM are only mandatory for
* EHT/MLO and break interoperability with many clients, so only default
* them on where they are both required and safe to offer: on Compatibility
* mode (sae-compat) BSSes that run an EHT htmode, which carry them in a
* separate RSN Override element that legacy clients ignore. They stay off
* for WPA3-Personal (sae) and Transition (sae-mixed) mode and on non-EHT
* BSSes. Explicit gcmp256 and sae_ext_key options override this per BSS.
*/
let compat = (config.auth_type == 'sae-compat');
config.gcmp256 ??= compat && wildcard(dev_config?.htmode ?? '', 'EHT*');
config.sae_ext_key ??= compat && wildcard(dev_config?.htmode ?? '', 'EHT*');
switch(config.auth_type) {
@@ -70,7 +71,7 @@ export function parse_encryption(config, dev_config, phy_features) {
config.wpa_pairwise = 'CCMP';
if (dev_config.band != '6g')
config.rsn_override_pairwise = 'CCMP';
if (phy_features?.cipher_gcmp256 && wildcard(dev_config.htmode ?? '', 'EHT*'))
if (config.gcmp256 && phy_features?.cipher_gcmp256)
config.rsn_override_pairwise_2 = 'GCMP-256';
break;
@@ -115,7 +116,7 @@ export function parse_encryption(config, dev_config, phy_features) {
config.wpa_pairwise ??= null;
else if (config.hw_mode == 'ad')
config.wpa_pairwise ??= 'GCMP';
else if (phy_features?.cipher_gcmp256)
else if (config.gcmp256 && phy_features?.cipher_gcmp256)
config.wpa_pairwise ??= 'GCMP-256 CCMP';
else
config.wpa_pairwise ??= 'CCMP';