* [PATCH v2 2/3] station: add handling for new NETCONFIG state
2024-01-05 14:47 [PATCH v2 1/3] station: add additional internal state, STATION_STATE_NETCONFIG James Prestwood
@ 2024-01-05 14:47 ` James Prestwood
2024-01-05 14:47 ` [PATCH v2 3/3] auto-t: add test for roaming + netconfig James Prestwood
2024-01-09 4:20 ` [PATCH v2 1/3] station: add additional internal state, STATION_STATE_NETCONFIG Denis Kenzior
2 siblings, 0 replies; 4+ messages in thread
From: James Prestwood @ 2024-01-05 14:47 UTC (permalink / raw)
To: iwd; +Cc: James Prestwood
There was an unhandled corner case if netconfig was running and
multiple roam conditions happened in sequence, all before netconfig
had completed. A single roam before netconfig was already handled
(23f0f5717c) but this did not take into account any additional roam
conditions.
If IWD is in this state, having started netconfig, then roamed, and
again restarted netconfig it is still in a roaming state which will
prevent any further roams. IWD will remain "stuck" on the current
BSS until netconfig completes or gets disconnected.
In addition the general state logic is wrong here. If IWD roams
prior to netconfig it should stay in a connecting state (from the
perspective of DBus).
To fix this a new internal station state was added (no changes to
the DBus API) to distinguish between a purely WiFi connecting state
(STATION_STATE_CONNECTING/AUTO) and netconfig
(STATION_STATE_NETCONFIG). This allows IWD roam as needed if
netconfig is still running. Also, some special handling was added so
the station state property remains in a "connected" state until
netconfig actually completes, regardless of roams.
For some background this scenario happens if the DHCP server goes
down for an extended period, e.g. if its being upgraded/serviced.
---
src/station.c | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
v2:
* Stay in a "connecting" state if roaming before netconfig from
a DBus property perspective.
* Minor changes using L_IN_SET
There are still improvements needed in this area, but this at
least fixes the major issues related to the state change and allowing
multiple roams. Still TODO:
* Add a netconfig timeout (in ELL)
* Put netconfig behind a wiphy work item. This requires some thought
since we'd still need to allow roam scans, but just not any other
scans/offchannel.
diff --git a/src/station.c b/src/station.c
index 68cac945..a6442d3e 100644
--- a/src/station.c
+++ b/src/station.c
@@ -1770,6 +1770,7 @@ static void station_reset_connection_state(struct station *station)
if (station->state == STATION_STATE_CONNECTED ||
station->state == STATION_STATE_CONNECTING ||
station->state == STATION_STATE_CONNECTING_AUTO ||
+ station->state == STATION_STATE_NETCONFIG ||
station_is_roaming(station))
network_disconnected(network);
}
@@ -2045,8 +2046,7 @@ static void station_netconfig_event_handler(enum netconfig_event event,
dbus_pending_reply(&station->connect_pending, reply);
}
- if (L_IN_SET(station->state, STATION_STATE_CONNECTING,
- STATION_STATE_CONNECTING_AUTO))
+ if (station->state == STATION_STATE_NETCONFIG)
network_connect_failed(station->connected_network,
false);
@@ -2072,9 +2072,14 @@ static bool netconfig_after_roam(struct station *station)
network_get_settings(network)))
return false;
- return netconfig_configure(station->netconfig,
+ if (!netconfig_configure(station->netconfig,
station_netconfig_event_handler,
- station);
+ station))
+ return false;
+
+ station_enter_state(station, STATION_STATE_NETCONFIG);
+
+ return true;
}
static void station_roamed(struct station *station)
@@ -3253,6 +3258,8 @@ static void station_connect_ok(struct station *station)
station_netconfig_event_handler,
station)))
return;
+
+ station_enter_state(station, STATION_STATE_NETCONFIG);
} else
station_enter_state(station, STATION_STATE_CONNECTED);
}
@@ -4064,8 +4071,10 @@ static struct l_dbus_message *station_dbus_scan(struct l_dbus *dbus,
if (station->dbus_scan_id)
return dbus_error_busy(message);
- if (station->state == STATION_STATE_CONNECTING ||
- station->state == STATION_STATE_CONNECTING_AUTO)
+ if (L_IN_SET(station->state, STATION_STATE_CONNECTING,
+ STATION_STATE_CONNECTING_AUTO,
+ STATION_STATE_NETCONFIG) ||
+ station_is_roaming(station))
return dbus_error_busy(message);
station->dbus_scan_subset_idx = 0;
@@ -4288,7 +4297,14 @@ static bool station_property_get_state(struct l_dbus *dbus,
case STATION_STATE_ROAMING:
case STATION_STATE_FT_ROAMING:
case STATION_STATE_FW_ROAMING:
- statestr = "roaming";
+ /*
+ * Stay in a connecting state if roaming before netconfig
+ * has finished
+ */
+ if (station->netconfig_after_roam)
+ statestr = "connecting";
+ else
+ statestr = "roaming";
break;
}
@@ -5022,8 +5038,10 @@ static struct l_dbus_message *station_debug_scan(struct l_dbus *dbus,
if (station->dbus_scan_id)
return dbus_error_busy(message);
- if (station->state == STATION_STATE_CONNECTING ||
- station->state == STATION_STATE_CONNECTING_AUTO)
+ if (L_IN_SET(station->state, STATION_STATE_CONNECTING,
+ STATION_STATE_CONNECTING_AUTO,
+ STATION_STATE_NETCONFIG) ||
+ station_is_roaming(station))
return dbus_error_busy(message);
if (!l_dbus_message_get_arguments(message, "aq", &iter))
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] auto-t: add test for roaming + netconfig
2024-01-05 14:47 [PATCH v2 1/3] station: add additional internal state, STATION_STATE_NETCONFIG James Prestwood
2024-01-05 14:47 ` [PATCH v2 2/3] station: add handling for new NETCONFIG state James Prestwood
@ 2024-01-05 14:47 ` James Prestwood
2024-01-09 4:20 ` [PATCH v2 1/3] station: add additional internal state, STATION_STATE_NETCONFIG Denis Kenzior
2 siblings, 0 replies; 4+ messages in thread
From: James Prestwood @ 2024-01-05 14:47 UTC (permalink / raw)
To: iwd; +Cc: James Prestwood
This test ensures IWD will continue to roam and restart netconfig if
roam conditions are met prior to netconfig finishing.
---
autotests/testNetconfigRoam/TestFT.psk | 2 +
.../testNetconfigRoam/ft-psk-ccmp-1.conf | 41 +++++++++
.../testNetconfigRoam/ft-psk-ccmp-2.conf | 41 +++++++++
autotests/testNetconfigRoam/hw.conf | 8 ++
autotests/testNetconfigRoam/main.conf | 3 +
.../testNetconfigRoam/netconfig_roam_test.py | 91 +++++++++++++++++++
6 files changed, 186 insertions(+)
create mode 100644 autotests/testNetconfigRoam/TestFT.psk
create mode 100644 autotests/testNetconfigRoam/ft-psk-ccmp-1.conf
create mode 100644 autotests/testNetconfigRoam/ft-psk-ccmp-2.conf
create mode 100644 autotests/testNetconfigRoam/hw.conf
create mode 100644 autotests/testNetconfigRoam/main.conf
create mode 100644 autotests/testNetconfigRoam/netconfig_roam_test.py
v2:
* Updated to check/ensure that IWD remains "connecting" even through
multiple roams.
diff --git a/autotests/testNetconfigRoam/TestFT.psk b/autotests/testNetconfigRoam/TestFT.psk
new file mode 100644
index 00000000..e82d1295
--- /dev/null
+++ b/autotests/testNetconfigRoam/TestFT.psk
@@ -0,0 +1,2 @@
+[Security]
+Passphrase=EasilyGuessedPassword
diff --git a/autotests/testNetconfigRoam/ft-psk-ccmp-1.conf b/autotests/testNetconfigRoam/ft-psk-ccmp-1.conf
new file mode 100644
index 00000000..b46d1f27
--- /dev/null
+++ b/autotests/testNetconfigRoam/ft-psk-ccmp-1.conf
@@ -0,0 +1,41 @@
+hw_mode=g
+channel=1
+ssid=TestFT
+utf8_ssid=1
+ctrl_interface=/var/run/hostapd
+
+r1_key_holder=120000000001
+nas_identifier=dummy1
+
+wpa=2
+# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
+# time but we want to force FT
+wpa_key_mgmt=FT-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=EasilyGuessedPassword
+ieee80211w=1
+rsn_preauth=1
+rsn_preauth_interfaces=lo
+disable_pmksa_caching=0
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+okc=1
+mobility_domain=1234
+reassociation_deadline=60000
+r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
+r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
+r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
+r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
+# Push mode only needed for 8021x, not PSK mode since msk already known
+pmk_r1_push=0
+# Allow locally generated FT response so we don't have to configure push/pull
+# between BSSes running as separate hostapd processes as in the test-runner
+# case. Only works with FT-PSK, otherwise brctl needs to be installed and
+# CONFIG_BRIDGE enabled in the kernel.
+ft_psk_generate_local=1
+rkh_pull_timeout=50
+ft_over_ds=0
+ap_table_expiration_time=36000
+ap_table_max_size=10
+rrm_neighbor_report=1
+ocv=1
diff --git a/autotests/testNetconfigRoam/ft-psk-ccmp-2.conf b/autotests/testNetconfigRoam/ft-psk-ccmp-2.conf
new file mode 100644
index 00000000..3e215457
--- /dev/null
+++ b/autotests/testNetconfigRoam/ft-psk-ccmp-2.conf
@@ -0,0 +1,41 @@
+hw_mode=g
+channel=2
+ssid=TestFT
+utf8_ssid=1
+ctrl_interface=/var/run/hostapd
+
+r1_key_holder=120000000002
+nas_identifier=dummy2
+
+wpa=2
+# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
+# time but we want to force FT
+wpa_key_mgmt=FT-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=EasilyGuessedPassword
+ieee80211w=1
+rsn_preauth=1
+rsn_preauth_interfaces=lo
+disable_pmksa_caching=0
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+okc=1
+mobility_domain=1234
+reassociation_deadline=60000
+r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
+r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
+r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
+r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
+# Push mode only needed for 8021x, not PSK mode since msk already known
+pmk_r1_push=0
+# Allow locally generated FT response so we don't have to configure push/pull
+# between BSSes running as separate hostapd processes as in the test-runner
+# case. Only works with FT-PSK, otherwise brctl needs to be installed and
+# CONFIG_BRIDGE enabled in the kernel.
+ft_psk_generate_local=1
+rkh_pull_timeout=50
+ft_over_ds=0
+ap_table_expiration_time=36000
+ap_table_max_size=10
+rrm_neighbor_report=1
+ocv=1
diff --git a/autotests/testNetconfigRoam/hw.conf b/autotests/testNetconfigRoam/hw.conf
new file mode 100644
index 00000000..c2b35d6e
--- /dev/null
+++ b/autotests/testNetconfigRoam/hw.conf
@@ -0,0 +1,8 @@
+[SETUP]
+num_radios=3
+start_iwd=0
+hwsim_medium=yes
+
+[HOSTAPD]
+rad0=ft-psk-ccmp-1.conf
+rad1=ft-psk-ccmp-2.conf
diff --git a/autotests/testNetconfigRoam/main.conf b/autotests/testNetconfigRoam/main.conf
new file mode 100644
index 00000000..aedd4ebd
--- /dev/null
+++ b/autotests/testNetconfigRoam/main.conf
@@ -0,0 +1,3 @@
+[General]
+EnableNetworkConfiguration=true
+RoamRetryInterval=1
diff --git a/autotests/testNetconfigRoam/netconfig_roam_test.py b/autotests/testNetconfigRoam/netconfig_roam_test.py
new file mode 100644
index 00000000..63e5eabf
--- /dev/null
+++ b/autotests/testNetconfigRoam/netconfig_roam_test.py
@@ -0,0 +1,91 @@
+#! /usr/bin/python3
+
+import unittest
+import sys, os
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from iwd import PSKAgent
+from iwd import NetworkType
+from iwd import DeviceState
+from hwsim import Hwsim
+from hostapd import HostapdCLI
+import testutil
+
+class Test(unittest.TestCase):
+ def test_roam_before_netconfig(self):
+ wd = IWD(True)
+
+ device = wd.list_devices(1)[0]
+ device.get_ordered_network('TestFT', full_scan=True)
+ device.connect_bssid(self.bss_hostapd[1].bssid)
+
+ self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}')
+ device.wait_for_event("connecting (netconfig)")
+
+ roam_to = 0
+ roam_from = 1
+
+ # Roam back and forth, ensuring that the state transitions between
+ # roaming and connecting (netconfig).
+ for _ in range(0, 5):
+ self.rules[roam_to].signal = -2000
+ self.rules[roam_from].signal = -8000
+
+ # Station should internally transition to roaming, but remain in a
+ # connecting state on DBus
+ device.wait_for_event("ft-roaming")
+ self.assertEqual(device.state, DeviceState.connecting)
+
+ self.bss_hostapd[roam_to].wait_for_event(f'AP-STA-CONNECTED {device.address}')
+ device.wait_for_event("connecting (netconfig)")
+
+ tmp = roam_from
+ roam_from = roam_to
+ roam_to = tmp
+
+ self.bss_hostapd[roam_from].deauthenticate(device.address)
+ condition = 'obj.state == DeviceState.disconnected'
+ wd.wait_for_object_condition(device, condition)
+
+ def tearDown(self):
+ os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
+ os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
+ os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
+ os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
+
+ @classmethod
+ def setUpClass(cls):
+ hwsim = Hwsim()
+
+ IWD.copy_to_storage('TestFT.psk')
+
+ cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
+ HostapdCLI(config='ft-psk-ccmp-2.conf') ]
+
+ rule0 = hwsim.rules.create()
+ rule0.source = cls.bss_hostapd[0].bssid
+ rule0.signal = -6000
+ rule0.enabled = True
+
+ rule1 = hwsim.rules.create()
+ rule1.source = cls.bss_hostapd[1].bssid
+ rule1.signal = -2000
+ rule1.enabled = True
+
+ cls.rules = [rule0, rule1]
+
+ cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
+ cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
+
+ HostapdCLI.group_neighbors(*cls.bss_hostapd)
+
+ @classmethod
+ def tearDownClass(cls):
+ IWD.clear_storage()
+ cls.bss_hostapd = None
+ cls.rules = None
+
+if __name__ == '__main__':
+ unittest.main(exit=True)
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread