From 75b8932b2051a0c4e41b94605201a3f60ebec940 Mon Sep 17 00:00:00 2001 From: bbedward Date: Sat, 5 Sep 2026 11:55:46 -0400 Subject: [PATCH] network: keep saved wifi profiles when NM fails with no-secrets fixes #3313 port 1.6 (cherry picked from commit c0f775ae49b05030ac1d7d5b37dc65ddd8a65edd) --- .../network/backend_networkmanager_state.go | 8 +++++++- .../backend_networkmanager_state_test.go | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/core/internal/server/network/backend_networkmanager_state.go b/core/internal/server/network/backend_networkmanager_state.go index 206c621e8..9422f67f0 100644 --- a/core/internal/server/network/backend_networkmanager_state.go +++ b/core/internal/server/network/backend_networkmanager_state.go @@ -183,6 +183,12 @@ func (b *NetworkManagerBackend) classifyNMStateReason(reason uint32) string { } } +// NM raises NO_SECRETS once auth retries run out on a saved profile too, not only +// on a dismissed prompt (nm-device-wifi.c handle_8021x_or_psk_auth_fail, #3313). +func forgetOnConnectFailure(reasonCode string, preExisting bool) bool { + return reasonCode == errdefs.ErrUserCanceled && !preExisting +} + // With several adapters, state must follow the associated device, not whichever // enumerated first (#2460). func (b *NetworkManagerBackend) wifiDeviceForState() (gonetworkmanager.Device, gonetworkmanager.DeviceWireless) { @@ -321,7 +327,7 @@ func (b *NetworkManagerBackend) updateWiFiState() error { b.state.ConnectingSSID = "" b.state.LastError = reasonCode - if reasonCode == errdefs.ErrUserCanceled { + if forgetOnConnectFailure(reasonCode, b.state.ConnectingPreExisting) { forgetSSID = connectingSSID } diff --git a/core/internal/server/network/backend_networkmanager_state_test.go b/core/internal/server/network/backend_networkmanager_state_test.go index 088934333..d11d3fd57 100644 --- a/core/internal/server/network/backend_networkmanager_state_test.go +++ b/core/internal/server/network/backend_networkmanager_state_test.go @@ -146,3 +146,23 @@ func TestNetworkManagerBackend_UpdateWiFiState_PicksConnectedDevice(t *testing.T assert.True(t, backend.state.WiFiConnected) assert.Equal(t, "wlan1", backend.state.WiFiDevice) } + +func TestForgetOnConnectFailure(t *testing.T) { + tests := []struct { + name string + reasonCode string + preExisting bool + want bool + }{ + {"cancelled prompt on freshly created profile", errdefs.ErrUserCanceled, false, true}, + {"no-secrets failure on saved profile", errdefs.ErrUserCanceled, true, false}, + {"bad credentials on freshly created profile", errdefs.ErrBadCredentials, false, false}, + {"generic failure on saved profile", errdefs.ErrConnectionFailed, true, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, forgetOnConnectFailure(tt.reasonCode, tt.preExisting)) + }) + } +}