* [RFC] dbus: expose per-BSS security capabilities
@ 2026-07-11 20:07 Алексей
2026-07-14 13:27 ` James Prestwood
0 siblings, 1 reply; 14+ messages in thread
From: Алексей @ 2026-07-11 20:07 UTC (permalink / raw)
To: iwd
Hi,
NetworkManager cannot currently distinguish WPA2-Personal, WPA3-Personal,
and WPA2/WPA3 transition networks when using its iwd backend.
iwd has the required information internally. scan_bss stores the WPA and
RSN information elements, and scan_bss_get_rsn_info() exposes the parsed AKM
and cipher information. However, the stable D-Bus API reduces all of these
personal network variants to Network.Type="psk". BasicServiceSet currently
exports only Address.
This causes a concrete integration failure. NetworkManager maps an iwd
Network with Type="psk" to NM_802_11_AP_SEC_KEY_MGMT_PSK. A saved NM profile
with 802-11-wireless-security.key-mgmt="sae" then fails the normal AP/profile
compatibility check and is removed from Device.AvailableConnections, even
while iwd is successfully connected to the same network using SAE.
Observed with NetworkManager 1.56.1 and iwd 3.12 on a WPA2/WPA3 transition
network:
NM profile key-mgmt: sae
iwd negotiated security: WPA3-Personal + FT
NM AP RsnFlags: 0x188 (CCMP + PSK, no SAE)
NM AvailableConnections: empty
Would it be acceptable to extend net.connman.iwd.BasicServiceSet with stable
WPA/RSN security capability information?
The information needs to include at least:
- advertised AKM suites (PSK, FT-PSK, SAE, FT-SAE, and so on)
- pairwise and group ciphers
- management frame protection capability and requirement
Per-BSS properties seem preferable to a Network-level value because BSSs in
the same ESS may advertise different capabilities. A consumer such as
NetworkManager can aggregate the capabilities when presenting the iwd
Network as one logical AP while leaving BSS selection and roaming to iwd.
One possible API shape would be an extensible read-only RSN dictionary on
BasicServiceSet, similar to:
RSN = {
"KeyManagement": ["psk", "sae", "ft-sae"],
"Pairwise": ["ccmp"],
"Group": "ccmp",
"ManagementFrameProtection": "optional"
}
The exact representation is the main subject of this RFC. Raw suite
selectors, separate properties, or an aggregate Network property may fit
iwd's API conventions better.
A corresponding NetworkManager change would consume these capabilities
instead of synthesizing PSK-only RsnFlags from Network.Type. Separately, NM
should preserve an SAE-only profile policy in the generated iwd profile by
using:
[Settings]
TransitionDisable=true
DisabledTransitionModes=personal
Related reports and downstream investigation:
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1489
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1693
https://invent.kde.org/plasma/plasma-nm/-/merge_requests/571
There was prior discussion indicating that additional BasicServiceSet
properties are welcome when the data already exists in scan_bss:
https://lore.kernel.org/iwd/97112988-3681-4192-abb2-9a9ee6d9552d@gmail.com/
If this direction is acceptable, I can follow up with the D-Bus
documentation, implementation, and tests after agreeing on the property
format.
Regards,
Aleks
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC] dbus: expose per-BSS security capabilities
2026-07-11 20:07 [RFC] dbus: expose per-BSS security capabilities Алексей
@ 2026-07-14 13:27 ` James Prestwood
2026-07-14 20:36 ` [PATCH 0/3] dbus: expose per-BSS RSN capabilities Алексей
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
0 siblings, 2 replies; 14+ messages in thread
From: James Prestwood @ 2026-07-14 13:27 UTC (permalink / raw)
To: Алексей, iwd
Hi,
On 7/11/26 1:07 PM, Алексей wrote:
> Hi,
>
> NetworkManager cannot currently distinguish WPA2-Personal, WPA3-Personal,
> and WPA2/WPA3 transition networks when using its iwd backend.
>
> iwd has the required information internally. scan_bss stores the WPA and
> RSN information elements, and scan_bss_get_rsn_info() exposes the parsed AKM
> and cipher information. However, the stable D-Bus API reduces all of these
> personal network variants to Network.Type="psk". BasicServiceSet currently
> exports only Address.
>
> This causes a concrete integration failure. NetworkManager maps an iwd
> Network with Type="psk" to NM_802_11_AP_SEC_KEY_MGMT_PSK. A saved NM profile
> with 802-11-wireless-security.key-mgmt="sae" then fails the normal AP/profile
> compatibility check and is removed from Device.AvailableConnections, even
> while iwd is successfully connected to the same network using SAE.
>
> Observed with NetworkManager 1.56.1 and iwd 3.12 on a WPA2/WPA3 transition
> network:
>
> NM profile key-mgmt: sae
> iwd negotiated security: WPA3-Personal + FT
> NM AP RsnFlags: 0x188 (CCMP + PSK, no SAE)
> NM AvailableConnections: empty
>
> Would it be acceptable to extend net.connman.iwd.BasicServiceSet with stable
> WPA/RSN security capability information?
>
> The information needs to include at least:
>
> - advertised AKM suites (PSK, FT-PSK, SAE, FT-SAE, and so on)
> - pairwise and group ciphers
> - management frame protection capability and requirement
>
> Per-BSS properties seem preferable to a Network-level value because BSSs in
> the same ESS may advertise different capabilities. A consumer such as
> NetworkManager can aggregate the capabilities when presenting the iwd
> Network as one logical AP while leaving BSS selection and roaming to iwd.
>
> One possible API shape would be an extensible read-only RSN dictionary on
> BasicServiceSet, similar to:
>
> RSN = {
> "KeyManagement": ["psk", "sae", "ft-sae"],
> "Pairwise": ["ccmp"],
> "Group": "ccmp",
> "ManagementFrameProtection": "optional"
> }
Extending the BasicServiceSet interface to include these properties
seems perfectly reasonable to me.
>
> The exact representation is the main subject of this RFC. Raw suite
> selectors, separate properties, or an aggregate Network property may fit
> iwd's API conventions better.
>
> A corresponding NetworkManager change would consume these capabilities
> instead of synthesizing PSK-only RsnFlags from Network.Type. Separately, NM
> should preserve an SAE-only profile policy in the generated iwd profile by
> using:
>
> [Settings]
> TransitionDisable=true
> DisabledTransitionModes=personal
>
> Related reports and downstream investigation:
>
> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1489
> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1693
> https://invent.kde.org/plasma/plasma-nm/-/merge_requests/571
>
> There was prior discussion indicating that additional BasicServiceSet
> properties are welcome when the data already exists in scan_bss:
>
> https://lore.kernel.org/iwd/97112988-3681-4192-abb2-9a9ee6d9552d@gmail.com/
>
> If this direction is acceptable, I can follow up with the D-Bus
> documentation, implementation, and tests after agreeing on the property
> format.
>
> Regards,
> Aleks
>
Thanks,
James
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 0/3] dbus: expose per-BSS RSN capabilities
2026-07-14 13:27 ` James Prestwood
@ 2026-07-14 20:36 ` Алексей
2026-07-14 20:37 ` [PATCH 1/3] network: expose RSN capabilities on BSS Алексей
` (2 more replies)
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
1 sibling, 3 replies; 14+ messages in thread
From: Алексей @ 2026-07-14 20:36 UTC (permalink / raw)
To: James Prestwood; +Cc: iwd
James, thanks for confirming that extending BasicServiceSet is a
reasonable approach.
Network.Type intentionally represents WPA2-Personal, WPA3-Personal, and
transition networks as "psk". This series exposes the RSN information
that iwd already retains for each BSS so consumers can distinguish those
networks without changing the existing Network API.
The optional BasicServiceSet.RSN dictionary uses the same KeyMgmt,
Pairwise, and Group fields and values as wpa_supplicant's BSS.RSN
property. NetworkManager can therefore reuse its existing parser rather
than add another translation layer. Older consumers ignore the optional
property, and consumers can retain their Network.Type fallback for older
iwd versions.
A corresponding NetworkManager series reads and combines the per-BSS
capabilities for its synthetic ESS access point. It will be submitted
separately after this API series.
Validation:
- iwd builds successfully with make -j4.
- On a physical WPA2/WPA3 transition network, an initial PSK connection
was reported as WPA2. After changing the saved profile to SAE, a
disconnect/reconnect through the stock Plasma applet completed without
a password prompt and was reported as WPA3-SAE.
- Cycling Wi-Fi subsequently auto-connected the SAE profile and kept it
visible as connected in the applet.
The new QEMU auto-t test was not run locally because /dev/kvm is not
available on the test machine.
RFC:
https://lore.kernel.org/iwd/CAMq8zouhDMRW4Q7qSpMCFftp21wCzuC%2BRaJKsKz0sUivGAQHXA@mail.gmail.com/
Related NetworkManager issues:
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1489
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1693
Aleks Man (3):
network: expose RSN capabilities on BSS
doc: document BasicServiceSet RSN property
auto-t: test BasicServiceSet RSN property
.../basic_service_set_rsn_test.py | 70 +++++++++++
autotests/testBasicServiceSetRSN/hw.conf | 9 ++
autotests/testBasicServiceSetRSN/ssidSAE.conf | 11 ++
.../ssidTransition.conf | 12 ++
.../testBasicServiceSetRSN/ssidWPA2.conf | 8 ++
doc/basic-service-set.txt | 23 ++++
src/network.c | 110 ++++++++++++++++++
7 files changed, 243 insertions(+)
create mode 100644
autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
create mode 100644 autotests/testBasicServiceSetRSN/hw.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidSAE.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidTransition.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidWPA2.conf
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/3] network: expose RSN capabilities on BSS
2026-07-14 20:36 ` [PATCH 0/3] dbus: expose per-BSS RSN capabilities Алексей
@ 2026-07-14 20:37 ` Алексей
2026-07-14 20:38 ` [PATCH 2/3] doc: document BasicServiceSet RSN property Алексей
2026-07-14 20:39 ` [PATCH 3/3] auto-t: test " Алексей
2 siblings, 0 replies; 14+ messages in thread
From: Алексей @ 2026-07-14 20:37 UTC (permalink / raw)
To: James Prestwood; +Cc: iwd
Network.Type intentionally groups all personal networks as "psk".
Consumers therefore cannot distinguish PSK, SAE, and transition BSSes
even though scan results retain the RSN IE.
Add an optional RSN dictionary to BasicServiceSet with the advertised
key management suites and pairwise and group ciphers. Use the same field
and value names as wpa_supplicant's BSS.RSN property so consumers can
share parsing logic.
Parse bss->rsne directly so legacy WPA capabilities are not exposed as
RSN.
---
src/network.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/src/network.c b/src/network.c
index a5a2375a..aa9e1281 100644
--- a/src/network.c
+++ b/src/network.c
@@ -2198,10 +2198,120 @@ static bool
network_bss_property_get_address(struct l_dbus *dbus,
return true;
}
+struct network_bss_suite_name {
+ uint32_t suite;
+ const char *name;
+};
+
+static const struct network_bss_suite_name network_bss_akm_names[] = {
+ { IE_RSN_AKM_SUITE_PSK, "wpa-psk" },
+ { IE_RSN_AKM_SUITE_FT_USING_PSK, "wpa-ft-psk" },
+ { IE_RSN_AKM_SUITE_PSK_SHA256, "wpa-psk-sha256" },
+ { IE_RSN_AKM_SUITE_8021X, "wpa-eap" },
+ { IE_RSN_AKM_SUITE_FT_OVER_8021X, "wpa-ft-eap" },
+ { IE_RSN_AKM_SUITE_8021X_SHA256, "wpa-eap-sha256" },
+ { IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA256, "wpa-eap-suite-b" },
+ { IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA384, "wpa-eap-suite-b-192" },
+ { IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384, "wpa-ft-eap-sha384" },
+ { IE_RSN_AKM_SUITE_FILS_SHA256, "wpa-fils-sha256" },
+ { IE_RSN_AKM_SUITE_FILS_SHA384, "wpa-fils-sha384" },
+ { IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256, "wpa-ft-fils-sha256" },
+ { IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384, "wpa-ft-fils-sha384" },
+ { IE_RSN_AKM_SUITE_SAE_SHA256, "sae" },
+ { IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256, "ft-sae" },
+ { IE_RSN_AKM_SUITE_OWE, "owe" },
+};
+
+static const struct network_bss_suite_name network_bss_pairwise_names[] = {
+ { IE_RSN_CIPHER_SUITE_TKIP, "tkip" },
+ { IE_RSN_CIPHER_SUITE_CCMP, "ccmp" },
+ { IE_RSN_CIPHER_SUITE_GCMP, "gcmp" },
+ { IE_RSN_CIPHER_SUITE_CCMP_256, "ccmp-256" },
+ { IE_RSN_CIPHER_SUITE_GCMP_256, "gcmp-256" },
+};
+
+static const struct network_bss_suite_name network_bss_group_names[] = {
+ { IE_RSN_CIPHER_SUITE_WEP40, "wep40" },
+ { IE_RSN_CIPHER_SUITE_WEP104, "wep104" },
+ { IE_RSN_CIPHER_SUITE_TKIP, "tkip" },
+ { IE_RSN_CIPHER_SUITE_CCMP, "ccmp" },
+ { IE_RSN_CIPHER_SUITE_GCMP, "gcmp" },
+ { IE_RSN_CIPHER_SUITE_CCMP_256, "ccmp-256" },
+ { IE_RSN_CIPHER_SUITE_GCMP_256, "gcmp-256" },
+};
+
+static void network_bss_append_suite_names(
+ struct l_dbus_message_builder *builder,
+ const char *name, uint32_t suites,
+ const struct network_bss_suite_name *names,
+ size_t names_len)
+{
+ size_t i;
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', name);
+ l_dbus_message_builder_enter_variant(builder, "as");
+ l_dbus_message_builder_enter_array(builder, "s");
+
+ for (i = 0; i < names_len; i++)
+ if (suites & names[i].suite)
+ l_dbus_message_builder_append_basic(builder, 's',
+ names[i].name);
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+}
+
+static const char *network_bss_group_cipher_name(
+ enum ie_rsn_cipher_suite cipher)
+{
+ size_t i;
+
+ for (i = 0; i < L_ARRAY_SIZE(network_bss_group_names); i++)
+ if (network_bss_group_names[i].suite == cipher)
+ return network_bss_group_names[i].name;
+
+ return "";
+}
+
+static bool network_bss_property_get_rsn(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ struct scan_bss *bss = user_data;
+ struct ie_rsn_info info;
+ const char *group;
+
+ if (!bss->rsne || ie_parse_rsne_from_data(bss->rsne, bss->rsne[1] + 2,
+ &info) < 0)
+ return false;
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ network_bss_append_suite_names(builder, "KeyMgmt", info.akm_suites,
+ network_bss_akm_names,
+ L_ARRAY_SIZE(network_bss_akm_names));
+ network_bss_append_suite_names(builder, "Pairwise",
+ info.pairwise_ciphers,
+ network_bss_pairwise_names,
+ L_ARRAY_SIZE(network_bss_pairwise_names));
+
+ group = network_bss_group_cipher_name(info.group_cipher);
+ dbus_append_dict_basic(builder, "Group", 's', group);
+
+ l_dbus_message_builder_leave_array(builder);
+
+ return true;
+}
+
static void setup_bss_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_property(interface, "Address", 0, "s",
network_bss_property_get_address, NULL);
+ l_dbus_interface_property(interface, "RSN", 0, "a{sv}",
+ network_bss_property_get_rsn, NULL);
}
static int network_init(void)
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/3] doc: document BasicServiceSet RSN property
2026-07-14 20:36 ` [PATCH 0/3] dbus: expose per-BSS RSN capabilities Алексей
2026-07-14 20:37 ` [PATCH 1/3] network: expose RSN capabilities on BSS Алексей
@ 2026-07-14 20:38 ` Алексей
2026-07-14 20:39 ` [PATCH 3/3] auto-t: test " Алексей
2 siblings, 0 replies; 14+ messages in thread
From: Алексей @ 2026-07-14 20:38 UTC (permalink / raw)
To: James Prestwood; +Cc: iwd
Describe the optional RSN dictionary and its KeyMgmt, Pairwise, and
Group entries.
---
doc/basic-service-set.txt | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/doc/basic-service-set.txt b/doc/basic-service-set.txt
index f827ca02..b4f2486f 100644
--- a/doc/basic-service-set.txt
+++ b/doc/basic-service-set.txt
@@ -8,3 +8,26 @@ Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}/Xxx
Properties string Address [readonly]
MAC address of BSS
+
+ dict RSN [readonly, optional]
+
+ Security capabilities advertised in the RSN information
+ element. The dictionary contains the following entries:
+
+ array(string) KeyMgmt
+
+ Key management suites. Values use the same names as
+ the wpa_supplicant D-Bus BSS.RSN property, such as
+ "wpa-psk", "wpa-ft-psk", "sae", "ft-sae",
+ "wpa-eap", and "owe".
+
+ array(string) Pairwise
+
+ Pairwise ciphers. Possible values are "tkip",
+ "ccmp", "gcmp", "ccmp-256", and "gcmp-256".
+
+ string Group
+
+ Group cipher. Possible values are "wep40", "wep104",
+ "tkip", "ccmp", "gcmp", "ccmp-256", and
+ "gcmp-256".
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/3] auto-t: test BasicServiceSet RSN property
2026-07-14 20:36 ` [PATCH 0/3] dbus: expose per-BSS RSN capabilities Алексей
2026-07-14 20:37 ` [PATCH 1/3] network: expose RSN capabilities on BSS Алексей
2026-07-14 20:38 ` [PATCH 2/3] doc: document BasicServiceSet RSN property Алексей
@ 2026-07-14 20:39 ` Алексей
2 siblings, 0 replies; 14+ messages in thread
From: Алексей @ 2026-07-14 20:39 UTC (permalink / raw)
To: James Prestwood; +Cc: iwd
Verify the exact D-Bus key management and cipher capabilities for
WPA2-PSK, SAE, and transition BSSes.
---
.../basic_service_set_rsn_test.py | 70 +++++++++++++++++++
autotests/testBasicServiceSetRSN/hw.conf | 9 +++
autotests/testBasicServiceSetRSN/ssidSAE.conf | 11 +++
.../ssidTransition.conf | 12 ++++
.../testBasicServiceSetRSN/ssidWPA2.conf | 8 +++
5 files changed, 110 insertions(+)
create mode 100644
autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
create mode 100644 autotests/testBasicServiceSetRSN/hw.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidSAE.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidTransition.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidWPA2.conf
diff --git a/autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
b/autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
new file mode 100644
index 00000000..20e0b62c
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
@@ -0,0 +1,70 @@
+#! /usr/bin/python3
+
+import unittest
+import sys
+
+import dbus
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from hwsim import Hwsim
+from hostapd import HostapdCLI
+
+BSS_INTERFACE = 'net.connman.iwd.BasicServiceSet'
+
+
+class Test(unittest.TestCase):
+ def _get_rsn(self, device, ssid):
+ ordered_network = device.get_ordered_network(ssid, full_scan=True)
+ network = ordered_network.network_object
+ self.assertEqual(len(network.extended_service_set), 1)
+
+ path = network.extended_service_set[0]
+ proxy = self.wd._bus.get_object(iwd.IWD_SERVICE, path)
+ properties = dbus.Interface(proxy, iwd.DBUS_PROPERTIES)
+
+ return properties.GetAll(BSS_INTERFACE)['RSN']
+
+ def test_rsn(self):
+ device = self.wd.list_devices(1)[0]
+
+ rsn = self._get_rsn(device, 'ssidWPA2')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])), {'wpa-psk'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ rsn = self._get_rsn(device, 'ssidSAE')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])), {'sae'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ rsn = self._get_rsn(device, 'ssidTransition')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])),
+ {'wpa-psk', 'sae'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ def setUp(self):
+ self.wd = IWD(True)
+
+ def tearDown(self):
+ self.wd.stop()
+ self.wd = None
+
+ @classmethod
+ def setUpClass(cls):
+ Hwsim()
+ cls.hostapd = [
+ HostapdCLI(config='ssidWPA2.conf'),
+ HostapdCLI(config='ssidSAE.conf'),
+ HostapdCLI(config='ssidTransition.conf'),
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.hostapd = None
+
+
+if __name__ == '__main__':
+ unittest.main(exit=True)
diff --git a/autotests/testBasicServiceSetRSN/hw.conf
b/autotests/testBasicServiceSetRSN/hw.conf
new file mode 100644
index 00000000..a43062d9
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/hw.conf
@@ -0,0 +1,9 @@
+[SETUP]
+num_radios=4
+hwsim_medium=yes
+start_iwd=no
+
+[HOSTAPD]
+rad0=ssidWPA2.conf
+rad1=ssidSAE.conf
+rad2=ssidTransition.conf
diff --git a/autotests/testBasicServiceSetRSN/ssidSAE.conf
b/autotests/testBasicServiceSetRSN/ssidSAE.conf
new file mode 100644
index 00000000..2ec9ae61
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidSAE.conf
@@ -0,0 +1,11 @@
+hw_mode=g
+channel=2
+ssid=ssidSAE
+
+wpa=2
+wpa_key_mgmt=SAE
+wpa_pairwise=CCMP
+sae_password=secret123
+sae_groups=19
+ieee80211w=2
+sae_pwe=0
diff --git a/autotests/testBasicServiceSetRSN/ssidTransition.conf
b/autotests/testBasicServiceSetRSN/ssidTransition.conf
new file mode 100644
index 00000000..00170772
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidTransition.conf
@@ -0,0 +1,12 @@
+hw_mode=g
+channel=3
+ssid=ssidTransition
+
+wpa=2
+wpa_key_mgmt=WPA-PSK SAE
+wpa_pairwise=CCMP
+wpa_passphrase=secret123
+sae_password=secret123
+sae_groups=19
+ieee80211w=1
+sae_pwe=0
diff --git a/autotests/testBasicServiceSetRSN/ssidWPA2.conf
b/autotests/testBasicServiceSetRSN/ssidWPA2.conf
new file mode 100644
index 00000000..d706142b
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidWPA2.conf
@@ -0,0 +1,8 @@
+hw_mode=g
+channel=1
+ssid=ssidWPA2
+
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=secret123
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities
2026-07-14 13:27 ` James Prestwood
2026-07-14 20:36 ` [PATCH 0/3] dbus: expose per-BSS RSN capabilities Алексей
@ 2026-07-14 21:12 ` Aleksman4o
2026-07-14 21:12 ` [PATCH v2 1/3] network: expose RSN capabilities on BSS Aleksman4o
` (3 more replies)
1 sibling, 4 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 21:12 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
James, thanks for confirming that extending BasicServiceSet is a
reasonable approach.
Network.Type intentionally represents WPA2-Personal, WPA3-Personal, and
transition networks as "psk". This series exposes the RSN information
that iwd already retains for each BSS so consumers can distinguish those
networks without changing the existing Network API.
The optional BasicServiceSet.RSN dictionary uses the same KeyMgmt,
Pairwise, and Group fields and values as wpa_supplicant's BSS.RSN
property. NetworkManager can therefore reuse its existing parser rather
than add another translation layer. Older consumers ignore the optional
property, and consumers can retain their Network.Type fallback for older
iwd versions.
A corresponding NetworkManager series reads and combines the per-BSS
capabilities for its synthetic ESS access point. It will be submitted
separately after this API series.
Validation:
- iwd builds successfully with make -j4.
- On a physical WPA2/WPA3 transition network, an initial PSK connection
was reported as WPA2. After changing the saved profile to SAE, a
disconnect/reconnect through the stock Plasma applet completed without
a password prompt and was reported as WPA3-SAE.
- Cycling Wi-Fi subsequently auto-connected the SAE profile and kept it
visible as connected in the applet.
The new QEMU auto-t test was not run locally because /dev/kvm is not
available on the test machine.
Changes in v2:
- Resend with git-send-email after the Gmail web client corrupted the
inline v1 patches. There are no code changes.
RFC:
https://lore.kernel.org/iwd/CAMq8zouhDMRW4Q7qSpMCFftp21wCzuC%2BRaJKsKz0sUivGAQHXA@mail.gmail.com/
Related NetworkManager issues:
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1489
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1693
Aleks Man (3):
network: expose RSN capabilities on BSS
doc: document BasicServiceSet RSN property
auto-t: test BasicServiceSet RSN property
.../basic_service_set_rsn_test.py | 70 +++++++++++
autotests/testBasicServiceSetRSN/hw.conf | 9 ++
autotests/testBasicServiceSetRSN/ssidSAE.conf | 11 ++
.../ssidTransition.conf | 12 ++
.../testBasicServiceSetRSN/ssidWPA2.conf | 8 ++
doc/basic-service-set.txt | 23 ++++
src/network.c | 110 ++++++++++++++++++
7 files changed, 243 insertions(+)
create mode 100644 autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
create mode 100644 autotests/testBasicServiceSetRSN/hw.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidSAE.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidTransition.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidWPA2.conf
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/3] network: expose RSN capabilities on BSS
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
@ 2026-07-14 21:12 ` Aleksman4o
2026-07-14 21:12 ` [PATCH v2 2/3] doc: document BasicServiceSet RSN property Aleksman4o
` (2 subsequent siblings)
3 siblings, 0 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 21:12 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
Network.Type intentionally groups all personal networks as "psk".
Consumers therefore cannot distinguish PSK, SAE, and transition BSSes
even though scan results retain the RSN IE.
Add an optional RSN dictionary to BasicServiceSet with the advertised
key management suites and pairwise and group ciphers. Use the same field
and value names as wpa_supplicant's BSS.RSN property so consumers can
share parsing logic.
Parse bss->rsne directly so legacy WPA capabilities are not exposed as
RSN.
---
src/network.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/src/network.c b/src/network.c
index a5a2375a..aa9e1281 100644
--- a/src/network.c
+++ b/src/network.c
@@ -2198,10 +2198,120 @@ static bool network_bss_property_get_address(struct l_dbus *dbus,
return true;
}
+struct network_bss_suite_name {
+ uint32_t suite;
+ const char *name;
+};
+
+static const struct network_bss_suite_name network_bss_akm_names[] = {
+ { IE_RSN_AKM_SUITE_PSK, "wpa-psk" },
+ { IE_RSN_AKM_SUITE_FT_USING_PSK, "wpa-ft-psk" },
+ { IE_RSN_AKM_SUITE_PSK_SHA256, "wpa-psk-sha256" },
+ { IE_RSN_AKM_SUITE_8021X, "wpa-eap" },
+ { IE_RSN_AKM_SUITE_FT_OVER_8021X, "wpa-ft-eap" },
+ { IE_RSN_AKM_SUITE_8021X_SHA256, "wpa-eap-sha256" },
+ { IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA256, "wpa-eap-suite-b" },
+ { IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA384, "wpa-eap-suite-b-192" },
+ { IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384, "wpa-ft-eap-sha384" },
+ { IE_RSN_AKM_SUITE_FILS_SHA256, "wpa-fils-sha256" },
+ { IE_RSN_AKM_SUITE_FILS_SHA384, "wpa-fils-sha384" },
+ { IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256, "wpa-ft-fils-sha256" },
+ { IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384, "wpa-ft-fils-sha384" },
+ { IE_RSN_AKM_SUITE_SAE_SHA256, "sae" },
+ { IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256, "ft-sae" },
+ { IE_RSN_AKM_SUITE_OWE, "owe" },
+};
+
+static const struct network_bss_suite_name network_bss_pairwise_names[] = {
+ { IE_RSN_CIPHER_SUITE_TKIP, "tkip" },
+ { IE_RSN_CIPHER_SUITE_CCMP, "ccmp" },
+ { IE_RSN_CIPHER_SUITE_GCMP, "gcmp" },
+ { IE_RSN_CIPHER_SUITE_CCMP_256, "ccmp-256" },
+ { IE_RSN_CIPHER_SUITE_GCMP_256, "gcmp-256" },
+};
+
+static const struct network_bss_suite_name network_bss_group_names[] = {
+ { IE_RSN_CIPHER_SUITE_WEP40, "wep40" },
+ { IE_RSN_CIPHER_SUITE_WEP104, "wep104" },
+ { IE_RSN_CIPHER_SUITE_TKIP, "tkip" },
+ { IE_RSN_CIPHER_SUITE_CCMP, "ccmp" },
+ { IE_RSN_CIPHER_SUITE_GCMP, "gcmp" },
+ { IE_RSN_CIPHER_SUITE_CCMP_256, "ccmp-256" },
+ { IE_RSN_CIPHER_SUITE_GCMP_256, "gcmp-256" },
+};
+
+static void network_bss_append_suite_names(
+ struct l_dbus_message_builder *builder,
+ const char *name, uint32_t suites,
+ const struct network_bss_suite_name *names,
+ size_t names_len)
+{
+ size_t i;
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', name);
+ l_dbus_message_builder_enter_variant(builder, "as");
+ l_dbus_message_builder_enter_array(builder, "s");
+
+ for (i = 0; i < names_len; i++)
+ if (suites & names[i].suite)
+ l_dbus_message_builder_append_basic(builder, 's',
+ names[i].name);
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+}
+
+static const char *network_bss_group_cipher_name(
+ enum ie_rsn_cipher_suite cipher)
+{
+ size_t i;
+
+ for (i = 0; i < L_ARRAY_SIZE(network_bss_group_names); i++)
+ if (network_bss_group_names[i].suite == cipher)
+ return network_bss_group_names[i].name;
+
+ return "";
+}
+
+static bool network_bss_property_get_rsn(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ struct scan_bss *bss = user_data;
+ struct ie_rsn_info info;
+ const char *group;
+
+ if (!bss->rsne || ie_parse_rsne_from_data(bss->rsne, bss->rsne[1] + 2,
+ &info) < 0)
+ return false;
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ network_bss_append_suite_names(builder, "KeyMgmt", info.akm_suites,
+ network_bss_akm_names,
+ L_ARRAY_SIZE(network_bss_akm_names));
+ network_bss_append_suite_names(builder, "Pairwise",
+ info.pairwise_ciphers,
+ network_bss_pairwise_names,
+ L_ARRAY_SIZE(network_bss_pairwise_names));
+
+ group = network_bss_group_cipher_name(info.group_cipher);
+ dbus_append_dict_basic(builder, "Group", 's', group);
+
+ l_dbus_message_builder_leave_array(builder);
+
+ return true;
+}
+
static void setup_bss_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_property(interface, "Address", 0, "s",
network_bss_property_get_address, NULL);
+ l_dbus_interface_property(interface, "RSN", 0, "a{sv}",
+ network_bss_property_get_rsn, NULL);
}
static int network_init(void)
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/3] doc: document BasicServiceSet RSN property
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
2026-07-14 21:12 ` [PATCH v2 1/3] network: expose RSN capabilities on BSS Aleksman4o
@ 2026-07-14 21:12 ` Aleksman4o
2026-07-14 21:12 ` [PATCH v2 3/3] auto-t: test " Aleksman4o
2026-07-14 22:48 ` [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
3 siblings, 0 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 21:12 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
Describe the optional RSN dictionary and its KeyMgmt, Pairwise, and
Group entries.
---
doc/basic-service-set.txt | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/doc/basic-service-set.txt b/doc/basic-service-set.txt
index f827ca02..b4f2486f 100644
--- a/doc/basic-service-set.txt
+++ b/doc/basic-service-set.txt
@@ -8,3 +8,26 @@ Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}/Xxx
Properties string Address [readonly]
MAC address of BSS
+
+ dict RSN [readonly, optional]
+
+ Security capabilities advertised in the RSN information
+ element. The dictionary contains the following entries:
+
+ array(string) KeyMgmt
+
+ Key management suites. Values use the same names as
+ the wpa_supplicant D-Bus BSS.RSN property, such as
+ "wpa-psk", "wpa-ft-psk", "sae", "ft-sae",
+ "wpa-eap", and "owe".
+
+ array(string) Pairwise
+
+ Pairwise ciphers. Possible values are "tkip",
+ "ccmp", "gcmp", "ccmp-256", and "gcmp-256".
+
+ string Group
+
+ Group cipher. Possible values are "wep40", "wep104",
+ "tkip", "ccmp", "gcmp", "ccmp-256", and
+ "gcmp-256".
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/3] auto-t: test BasicServiceSet RSN property
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
2026-07-14 21:12 ` [PATCH v2 1/3] network: expose RSN capabilities on BSS Aleksman4o
2026-07-14 21:12 ` [PATCH v2 2/3] doc: document BasicServiceSet RSN property Aleksman4o
@ 2026-07-14 21:12 ` Aleksman4o
2026-07-14 22:48 ` [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
3 siblings, 0 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 21:12 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
Verify the exact D-Bus key management and cipher capabilities for
WPA2-PSK, SAE, and transition BSSes.
---
.../basic_service_set_rsn_test.py | 70 +++++++++++++++++++
autotests/testBasicServiceSetRSN/hw.conf | 9 +++
autotests/testBasicServiceSetRSN/ssidSAE.conf | 11 +++
.../ssidTransition.conf | 12 ++++
.../testBasicServiceSetRSN/ssidWPA2.conf | 8 +++
5 files changed, 110 insertions(+)
create mode 100644 autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
create mode 100644 autotests/testBasicServiceSetRSN/hw.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidSAE.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidTransition.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidWPA2.conf
diff --git a/autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py b/autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
new file mode 100644
index 00000000..20e0b62c
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/basic_service_set_rsn_test.py
@@ -0,0 +1,70 @@
+#! /usr/bin/python3
+
+import unittest
+import sys
+
+import dbus
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from hwsim import Hwsim
+from hostapd import HostapdCLI
+
+BSS_INTERFACE = 'net.connman.iwd.BasicServiceSet'
+
+
+class Test(unittest.TestCase):
+ def _get_rsn(self, device, ssid):
+ ordered_network = device.get_ordered_network(ssid, full_scan=True)
+ network = ordered_network.network_object
+ self.assertEqual(len(network.extended_service_set), 1)
+
+ path = network.extended_service_set[0]
+ proxy = self.wd._bus.get_object(iwd.IWD_SERVICE, path)
+ properties = dbus.Interface(proxy, iwd.DBUS_PROPERTIES)
+
+ return properties.GetAll(BSS_INTERFACE)['RSN']
+
+ def test_rsn(self):
+ device = self.wd.list_devices(1)[0]
+
+ rsn = self._get_rsn(device, 'ssidWPA2')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])), {'wpa-psk'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ rsn = self._get_rsn(device, 'ssidSAE')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])), {'sae'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ rsn = self._get_rsn(device, 'ssidTransition')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])),
+ {'wpa-psk', 'sae'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ def setUp(self):
+ self.wd = IWD(True)
+
+ def tearDown(self):
+ self.wd.stop()
+ self.wd = None
+
+ @classmethod
+ def setUpClass(cls):
+ Hwsim()
+ cls.hostapd = [
+ HostapdCLI(config='ssidWPA2.conf'),
+ HostapdCLI(config='ssidSAE.conf'),
+ HostapdCLI(config='ssidTransition.conf'),
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.hostapd = None
+
+
+if __name__ == '__main__':
+ unittest.main(exit=True)
diff --git a/autotests/testBasicServiceSetRSN/hw.conf b/autotests/testBasicServiceSetRSN/hw.conf
new file mode 100644
index 00000000..a43062d9
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/hw.conf
@@ -0,0 +1,9 @@
+[SETUP]
+num_radios=4
+hwsim_medium=yes
+start_iwd=no
+
+[HOSTAPD]
+rad0=ssidWPA2.conf
+rad1=ssidSAE.conf
+rad2=ssidTransition.conf
diff --git a/autotests/testBasicServiceSetRSN/ssidSAE.conf b/autotests/testBasicServiceSetRSN/ssidSAE.conf
new file mode 100644
index 00000000..2ec9ae61
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidSAE.conf
@@ -0,0 +1,11 @@
+hw_mode=g
+channel=2
+ssid=ssidSAE
+
+wpa=2
+wpa_key_mgmt=SAE
+wpa_pairwise=CCMP
+sae_password=secret123
+sae_groups=19
+ieee80211w=2
+sae_pwe=0
diff --git a/autotests/testBasicServiceSetRSN/ssidTransition.conf b/autotests/testBasicServiceSetRSN/ssidTransition.conf
new file mode 100644
index 00000000..00170772
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidTransition.conf
@@ -0,0 +1,12 @@
+hw_mode=g
+channel=3
+ssid=ssidTransition
+
+wpa=2
+wpa_key_mgmt=WPA-PSK SAE
+wpa_pairwise=CCMP
+wpa_passphrase=secret123
+sae_password=secret123
+sae_groups=19
+ieee80211w=1
+sae_pwe=0
diff --git a/autotests/testBasicServiceSetRSN/ssidWPA2.conf b/autotests/testBasicServiceSetRSN/ssidWPA2.conf
new file mode 100644
index 00000000..d706142b
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidWPA2.conf
@@ -0,0 +1,8 @@
+hw_mode=g
+channel=1
+ssid=ssidWPA2
+
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=secret123
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
` (2 preceding siblings ...)
2026-07-14 21:12 ` [PATCH v2 3/3] auto-t: test " Aleksman4o
@ 2026-07-14 22:48 ` Aleksman4o
2026-07-14 22:48 ` [PATCH v3 1/3] network: expose RSN capabilities on BSS Aleksman4o
` (2 more replies)
3 siblings, 3 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 22:48 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
James, thanks for confirming that extending BasicServiceSet is a
reasonable approach.
Network.Type intentionally represents WPA2-Personal, WPA3-Personal, and
transition networks as "psk". This series exposes the RSN information
that iwd already retains for each BSS so consumers can distinguish those
networks without changing the existing Network API.
The optional BasicServiceSet.RSN dictionary uses the same KeyMgmt,
Pairwise, and Group fields and values as wpa_supplicant's BSS.RSN
property. NetworkManager can therefore reuse its existing parser rather
than add another translation layer. Older consumers ignore the optional
property, and consumers can retain their Network.Type fallback for older
iwd versions.
A corresponding NetworkManager series reads and combines the per-BSS
capabilities for its synthetic ESS access point. It will be submitted
separately after this API series.
Validation:
- iwd builds successfully with make -j4.
- On a physical WPA2/WPA3 transition network, an initial PSK connection
was reported as WPA2. After changing the saved profile to SAE, a
disconnect/reconnect through the stock Plasma applet completed without
a password prompt and was reported as WPA3-SAE.
- Cycling Wi-Fi subsequently auto-connected the SAE profile and kept it
visible as connected in the applet.
- The upstream CI auto-t runner passed the v2 series.
Changes in v3:
- Shorten the auto-t filename so the generated patch metadata complies
with GitLint's 80-column limit. There are no code changes.
Changes in v2:
- Resend with git-send-email after the Gmail web client corrupted the
inline v1 patches. There are no code changes.
RFC:
https://lore.kernel.org/iwd/CAMq8zouhDMRW4Q7qSpMCFftp21wCzuC%2BRaJKsKz0sUivGAQHXA@mail.gmail.com/
Related NetworkManager issues:
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1489
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1693
Aleks Man (3):
network: expose RSN capabilities on BSS
doc: document BasicServiceSet RSN property
auto-t: test BasicServiceSet RSN property
.../testBasicServiceSetRSN/bss_rsn_test.py | 70 +++++++++++
autotests/testBasicServiceSetRSN/hw.conf | 9 ++
autotests/testBasicServiceSetRSN/ssidSAE.conf | 11 ++
.../ssidTransition.conf | 12 ++
.../testBasicServiceSetRSN/ssidWPA2.conf | 8 ++
doc/basic-service-set.txt | 23 ++++
src/network.c | 110 ++++++++++++++++++
7 files changed, 243 insertions(+)
create mode 100644 autotests/testBasicServiceSetRSN/bss_rsn_test.py
create mode 100644 autotests/testBasicServiceSetRSN/hw.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidSAE.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidTransition.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidWPA2.conf
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/3] network: expose RSN capabilities on BSS
2026-07-14 22:48 ` [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
@ 2026-07-14 22:48 ` Aleksman4o
2026-07-14 22:48 ` [PATCH v3 2/3] doc: document BasicServiceSet RSN property Aleksman4o
2026-07-14 22:48 ` [PATCH v3 3/3] auto-t: test " Aleksman4o
2 siblings, 0 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 22:48 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
Network.Type intentionally groups all personal networks as "psk".
Consumers therefore cannot distinguish PSK, SAE, and transition BSSes
even though scan results retain the RSN IE.
Add an optional RSN dictionary to BasicServiceSet with the advertised
key management suites and pairwise and group ciphers. Use the same field
and value names as wpa_supplicant's BSS.RSN property so consumers can
share parsing logic.
Parse bss->rsne directly so legacy WPA capabilities are not exposed as
RSN.
---
src/network.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/src/network.c b/src/network.c
index a5a2375a..aa9e1281 100644
--- a/src/network.c
+++ b/src/network.c
@@ -2198,10 +2198,120 @@ static bool network_bss_property_get_address(struct l_dbus *dbus,
return true;
}
+struct network_bss_suite_name {
+ uint32_t suite;
+ const char *name;
+};
+
+static const struct network_bss_suite_name network_bss_akm_names[] = {
+ { IE_RSN_AKM_SUITE_PSK, "wpa-psk" },
+ { IE_RSN_AKM_SUITE_FT_USING_PSK, "wpa-ft-psk" },
+ { IE_RSN_AKM_SUITE_PSK_SHA256, "wpa-psk-sha256" },
+ { IE_RSN_AKM_SUITE_8021X, "wpa-eap" },
+ { IE_RSN_AKM_SUITE_FT_OVER_8021X, "wpa-ft-eap" },
+ { IE_RSN_AKM_SUITE_8021X_SHA256, "wpa-eap-sha256" },
+ { IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA256, "wpa-eap-suite-b" },
+ { IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA384, "wpa-eap-suite-b-192" },
+ { IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384, "wpa-ft-eap-sha384" },
+ { IE_RSN_AKM_SUITE_FILS_SHA256, "wpa-fils-sha256" },
+ { IE_RSN_AKM_SUITE_FILS_SHA384, "wpa-fils-sha384" },
+ { IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256, "wpa-ft-fils-sha256" },
+ { IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384, "wpa-ft-fils-sha384" },
+ { IE_RSN_AKM_SUITE_SAE_SHA256, "sae" },
+ { IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256, "ft-sae" },
+ { IE_RSN_AKM_SUITE_OWE, "owe" },
+};
+
+static const struct network_bss_suite_name network_bss_pairwise_names[] = {
+ { IE_RSN_CIPHER_SUITE_TKIP, "tkip" },
+ { IE_RSN_CIPHER_SUITE_CCMP, "ccmp" },
+ { IE_RSN_CIPHER_SUITE_GCMP, "gcmp" },
+ { IE_RSN_CIPHER_SUITE_CCMP_256, "ccmp-256" },
+ { IE_RSN_CIPHER_SUITE_GCMP_256, "gcmp-256" },
+};
+
+static const struct network_bss_suite_name network_bss_group_names[] = {
+ { IE_RSN_CIPHER_SUITE_WEP40, "wep40" },
+ { IE_RSN_CIPHER_SUITE_WEP104, "wep104" },
+ { IE_RSN_CIPHER_SUITE_TKIP, "tkip" },
+ { IE_RSN_CIPHER_SUITE_CCMP, "ccmp" },
+ { IE_RSN_CIPHER_SUITE_GCMP, "gcmp" },
+ { IE_RSN_CIPHER_SUITE_CCMP_256, "ccmp-256" },
+ { IE_RSN_CIPHER_SUITE_GCMP_256, "gcmp-256" },
+};
+
+static void network_bss_append_suite_names(
+ struct l_dbus_message_builder *builder,
+ const char *name, uint32_t suites,
+ const struct network_bss_suite_name *names,
+ size_t names_len)
+{
+ size_t i;
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', name);
+ l_dbus_message_builder_enter_variant(builder, "as");
+ l_dbus_message_builder_enter_array(builder, "s");
+
+ for (i = 0; i < names_len; i++)
+ if (suites & names[i].suite)
+ l_dbus_message_builder_append_basic(builder, 's',
+ names[i].name);
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+}
+
+static const char *network_bss_group_cipher_name(
+ enum ie_rsn_cipher_suite cipher)
+{
+ size_t i;
+
+ for (i = 0; i < L_ARRAY_SIZE(network_bss_group_names); i++)
+ if (network_bss_group_names[i].suite == cipher)
+ return network_bss_group_names[i].name;
+
+ return "";
+}
+
+static bool network_bss_property_get_rsn(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ struct scan_bss *bss = user_data;
+ struct ie_rsn_info info;
+ const char *group;
+
+ if (!bss->rsne || ie_parse_rsne_from_data(bss->rsne, bss->rsne[1] + 2,
+ &info) < 0)
+ return false;
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ network_bss_append_suite_names(builder, "KeyMgmt", info.akm_suites,
+ network_bss_akm_names,
+ L_ARRAY_SIZE(network_bss_akm_names));
+ network_bss_append_suite_names(builder, "Pairwise",
+ info.pairwise_ciphers,
+ network_bss_pairwise_names,
+ L_ARRAY_SIZE(network_bss_pairwise_names));
+
+ group = network_bss_group_cipher_name(info.group_cipher);
+ dbus_append_dict_basic(builder, "Group", 's', group);
+
+ l_dbus_message_builder_leave_array(builder);
+
+ return true;
+}
+
static void setup_bss_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_property(interface, "Address", 0, "s",
network_bss_property_get_address, NULL);
+ l_dbus_interface_property(interface, "RSN", 0, "a{sv}",
+ network_bss_property_get_rsn, NULL);
}
static int network_init(void)
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 2/3] doc: document BasicServiceSet RSN property
2026-07-14 22:48 ` [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
2026-07-14 22:48 ` [PATCH v3 1/3] network: expose RSN capabilities on BSS Aleksman4o
@ 2026-07-14 22:48 ` Aleksman4o
2026-07-14 22:48 ` [PATCH v3 3/3] auto-t: test " Aleksman4o
2 siblings, 0 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 22:48 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
Describe the optional RSN dictionary and its KeyMgmt, Pairwise, and
Group entries.
---
doc/basic-service-set.txt | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/doc/basic-service-set.txt b/doc/basic-service-set.txt
index f827ca02..b4f2486f 100644
--- a/doc/basic-service-set.txt
+++ b/doc/basic-service-set.txt
@@ -8,3 +8,26 @@ Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}/Xxx
Properties string Address [readonly]
MAC address of BSS
+
+ dict RSN [readonly, optional]
+
+ Security capabilities advertised in the RSN information
+ element. The dictionary contains the following entries:
+
+ array(string) KeyMgmt
+
+ Key management suites. Values use the same names as
+ the wpa_supplicant D-Bus BSS.RSN property, such as
+ "wpa-psk", "wpa-ft-psk", "sae", "ft-sae",
+ "wpa-eap", and "owe".
+
+ array(string) Pairwise
+
+ Pairwise ciphers. Possible values are "tkip",
+ "ccmp", "gcmp", "ccmp-256", and "gcmp-256".
+
+ string Group
+
+ Group cipher. Possible values are "wep40", "wep104",
+ "tkip", "ccmp", "gcmp", "ccmp-256", and
+ "gcmp-256".
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 3/3] auto-t: test BasicServiceSet RSN property
2026-07-14 22:48 ` [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
2026-07-14 22:48 ` [PATCH v3 1/3] network: expose RSN capabilities on BSS Aleksman4o
2026-07-14 22:48 ` [PATCH v3 2/3] doc: document BasicServiceSet RSN property Aleksman4o
@ 2026-07-14 22:48 ` Aleksman4o
2 siblings, 0 replies; 14+ messages in thread
From: Aleksman4o @ 2026-07-14 22:48 UTC (permalink / raw)
To: iwd; +Cc: Aleks Man, prestwoj
From: Aleks Man <aleksman4o@gmail.com>
Verify the exact D-Bus key management and cipher capabilities for
WPA2-PSK, SAE, and transition BSSes.
---
.../testBasicServiceSetRSN/bss_rsn_test.py | 70 +++++++++++++++++++
autotests/testBasicServiceSetRSN/hw.conf | 9 +++
autotests/testBasicServiceSetRSN/ssidSAE.conf | 11 +++
.../ssidTransition.conf | 12 ++++
.../testBasicServiceSetRSN/ssidWPA2.conf | 8 +++
5 files changed, 110 insertions(+)
create mode 100644 autotests/testBasicServiceSetRSN/bss_rsn_test.py
create mode 100644 autotests/testBasicServiceSetRSN/hw.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidSAE.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidTransition.conf
create mode 100644 autotests/testBasicServiceSetRSN/ssidWPA2.conf
diff --git a/autotests/testBasicServiceSetRSN/bss_rsn_test.py b/autotests/testBasicServiceSetRSN/bss_rsn_test.py
new file mode 100644
index 00000000..20e0b62c
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/bss_rsn_test.py
@@ -0,0 +1,70 @@
+#! /usr/bin/python3
+
+import unittest
+import sys
+
+import dbus
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from hwsim import Hwsim
+from hostapd import HostapdCLI
+
+BSS_INTERFACE = 'net.connman.iwd.BasicServiceSet'
+
+
+class Test(unittest.TestCase):
+ def _get_rsn(self, device, ssid):
+ ordered_network = device.get_ordered_network(ssid, full_scan=True)
+ network = ordered_network.network_object
+ self.assertEqual(len(network.extended_service_set), 1)
+
+ path = network.extended_service_set[0]
+ proxy = self.wd._bus.get_object(iwd.IWD_SERVICE, path)
+ properties = dbus.Interface(proxy, iwd.DBUS_PROPERTIES)
+
+ return properties.GetAll(BSS_INTERFACE)['RSN']
+
+ def test_rsn(self):
+ device = self.wd.list_devices(1)[0]
+
+ rsn = self._get_rsn(device, 'ssidWPA2')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])), {'wpa-psk'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ rsn = self._get_rsn(device, 'ssidSAE')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])), {'sae'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ rsn = self._get_rsn(device, 'ssidTransition')
+ self.assertEqual(set(map(str, rsn['KeyMgmt'])),
+ {'wpa-psk', 'sae'})
+ self.assertEqual(set(map(str, rsn['Pairwise'])), {'ccmp'})
+ self.assertEqual(str(rsn['Group']), 'ccmp')
+
+ def setUp(self):
+ self.wd = IWD(True)
+
+ def tearDown(self):
+ self.wd.stop()
+ self.wd = None
+
+ @classmethod
+ def setUpClass(cls):
+ Hwsim()
+ cls.hostapd = [
+ HostapdCLI(config='ssidWPA2.conf'),
+ HostapdCLI(config='ssidSAE.conf'),
+ HostapdCLI(config='ssidTransition.conf'),
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.hostapd = None
+
+
+if __name__ == '__main__':
+ unittest.main(exit=True)
diff --git a/autotests/testBasicServiceSetRSN/hw.conf b/autotests/testBasicServiceSetRSN/hw.conf
new file mode 100644
index 00000000..a43062d9
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/hw.conf
@@ -0,0 +1,9 @@
+[SETUP]
+num_radios=4
+hwsim_medium=yes
+start_iwd=no
+
+[HOSTAPD]
+rad0=ssidWPA2.conf
+rad1=ssidSAE.conf
+rad2=ssidTransition.conf
diff --git a/autotests/testBasicServiceSetRSN/ssidSAE.conf b/autotests/testBasicServiceSetRSN/ssidSAE.conf
new file mode 100644
index 00000000..2ec9ae61
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidSAE.conf
@@ -0,0 +1,11 @@
+hw_mode=g
+channel=2
+ssid=ssidSAE
+
+wpa=2
+wpa_key_mgmt=SAE
+wpa_pairwise=CCMP
+sae_password=secret123
+sae_groups=19
+ieee80211w=2
+sae_pwe=0
diff --git a/autotests/testBasicServiceSetRSN/ssidTransition.conf b/autotests/testBasicServiceSetRSN/ssidTransition.conf
new file mode 100644
index 00000000..00170772
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidTransition.conf
@@ -0,0 +1,12 @@
+hw_mode=g
+channel=3
+ssid=ssidTransition
+
+wpa=2
+wpa_key_mgmt=WPA-PSK SAE
+wpa_pairwise=CCMP
+wpa_passphrase=secret123
+sae_password=secret123
+sae_groups=19
+ieee80211w=1
+sae_pwe=0
diff --git a/autotests/testBasicServiceSetRSN/ssidWPA2.conf b/autotests/testBasicServiceSetRSN/ssidWPA2.conf
new file mode 100644
index 00000000..d706142b
--- /dev/null
+++ b/autotests/testBasicServiceSetRSN/ssidWPA2.conf
@@ -0,0 +1,8 @@
+hw_mode=g
+channel=1
+ssid=ssidWPA2
+
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=secret123
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-07-14 22:50 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-11 20:07 [RFC] dbus: expose per-BSS security capabilities Алексей
2026-07-14 13:27 ` James Prestwood
2026-07-14 20:36 ` [PATCH 0/3] dbus: expose per-BSS RSN capabilities Алексей
2026-07-14 20:37 ` [PATCH 1/3] network: expose RSN capabilities on BSS Алексей
2026-07-14 20:38 ` [PATCH 2/3] doc: document BasicServiceSet RSN property Алексей
2026-07-14 20:39 ` [PATCH 3/3] auto-t: test " Алексей
2026-07-14 21:12 ` [PATCH v2 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
2026-07-14 21:12 ` [PATCH v2 1/3] network: expose RSN capabilities on BSS Aleksman4o
2026-07-14 21:12 ` [PATCH v2 2/3] doc: document BasicServiceSet RSN property Aleksman4o
2026-07-14 21:12 ` [PATCH v2 3/3] auto-t: test " Aleksman4o
2026-07-14 22:48 ` [PATCH v3 0/3] dbus: expose per-BSS RSN capabilities Aleksman4o
2026-07-14 22:48 ` [PATCH v3 1/3] network: expose RSN capabilities on BSS Aleksman4o
2026-07-14 22:48 ` [PATCH v3 2/3] doc: document BasicServiceSet RSN property Aleksman4o
2026-07-14 22:48 ` [PATCH v3 3/3] auto-t: test " Aleksman4o
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox