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)) + }) + } +}