From dca1bd35917710900e9b4f97c91c2d9cbeca015b Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 27 Aug 2026 10:37:57 -0400 Subject: [PATCH] network: report wifi state from the associated adapter fixes #2460 --- .../network/backend_networkmanager_state.go | 58 ++++++++++++++++--- .../backend_networkmanager_state_test.go | 31 ++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/core/internal/server/network/backend_networkmanager_state.go b/core/internal/server/network/backend_networkmanager_state.go index 61f676f67..e884ee8f0 100644 --- a/core/internal/server/network/backend_networkmanager_state.go +++ b/core/internal/server/network/backend_networkmanager_state.go @@ -1,6 +1,7 @@ package network import ( + "sort" "time" "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" @@ -146,12 +147,51 @@ func (b *NetworkManagerBackend) classifyNMStateReason(reason uint32) string { } } -func (b *NetworkManagerBackend) updateWiFiState() error { - if b.wifiDevice == nil { - return nil +// With several adapters, state must follow the associated device, not whichever +// enumerated first (#2460). +func (b *NetworkManagerBackend) wifiDeviceForState() (gonetworkmanager.Device, gonetworkmanager.DeviceWireless) { + var fallbackDev gonetworkmanager.Device + if b.wifiDevice != nil { + fallbackDev = b.wifiDevice.(gonetworkmanager.Device) + } + var fallbackWireless gonetworkmanager.DeviceWireless + if b.wifiDev != nil { + fallbackWireless = b.wifiDev.(gonetworkmanager.DeviceWireless) } - dev := b.wifiDevice.(gonetworkmanager.Device) + snapshot := b.wifiDevicesSnapshot() + if len(snapshot) < 2 { + return fallbackDev, fallbackWireless + } + + apMode := b.activeAPModeWiFiDevicePaths() + names := make([]string, 0, len(snapshot)) + for name := range snapshot { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + info := snapshot[name] + if info.device == nil { + continue + } + state, err := info.device.GetPropertyState() + if err != nil || state != gonetworkmanager.NmDeviceStateActivated { + continue + } + if apMode[string(info.device.GetPath())] { + continue + } + return info.device, info.wireless + } + return fallbackDev, fallbackWireless +} + +func (b *NetworkManagerBackend) updateWiFiState() error { + dev, wireless := b.wifiDeviceForState() + if dev == nil { + return nil + } iface, err := dev.GetPropertyInterface() if err != nil { @@ -177,9 +217,13 @@ func (b *NetworkManagerBackend) updateWiFiState() error { var signal uint8 if connected { - if err := b.ensureWiFiDevice(); err == nil && b.wifiDev != nil { - w := b.wifiDev.(gonetworkmanager.DeviceWireless) - activeAP, err := w.GetPropertyActiveAccessPoint() + if wireless == nil { + if err := b.ensureWiFiDevice(); err == nil && b.wifiDev != nil { + wireless = b.wifiDev.(gonetworkmanager.DeviceWireless) + } + } + if wireless != nil { + activeAP, err := wireless.GetPropertyActiveAccessPoint() if err == nil && activeAP != nil && activeAP.GetPath() != "/" { ssid, _ = activeAP.GetPropertySSID() signal, _ = activeAP.GetPropertyStrength() diff --git a/core/internal/server/network/backend_networkmanager_state_test.go b/core/internal/server/network/backend_networkmanager_state_test.go index 27027e7e6..088934333 100644 --- a/core/internal/server/network/backend_networkmanager_state_test.go +++ b/core/internal/server/network/backend_networkmanager_state_test.go @@ -115,3 +115,34 @@ func TestNetworkManagerBackend_UpdatePrimaryConnection_TypeMapping(t *testing.T) }) } } + +func TestNetworkManagerBackend_UpdateWiFiState_PicksConnectedDevice(t *testing.T) { + mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) + backend, err := NewNetworkManagerBackend(mockNM) + assert.NoError(t, err) + + first := mock_gonetworkmanager.NewMockDevice(t) + first.EXPECT().GetPropertyState().Return(gonetworkmanager.NmDeviceStateDisconnected, nil) + + second := mock_gonetworkmanager.NewMockDevice(t) + second.EXPECT().GetPropertyState().Return(gonetworkmanager.NmDeviceStateActivated, nil) + second.EXPECT().GetPath().Return("/org/freedesktop/NetworkManager/Devices/2") + second.EXPECT().GetPropertyInterface().Return("wlan1", nil) + second.EXPECT().GetPropertyIP4Config().Return(nil, nil) + + secondWireless := mock_gonetworkmanager.NewMockDeviceWireless(t) + secondWireless.EXPECT().GetPropertyActiveAccessPoint().Return(nil, nil) + + mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil) + + backend.setWifiDeviceInfo("wlan0", &wifiDeviceInfo{device: first, name: "wlan0"}) + backend.setWifiDeviceInfo("wlan1", &wifiDeviceInfo{device: second, wireless: secondWireless, name: "wlan1"}) + backend.wifiDevice = first + + assert.NoError(t, backend.updateWiFiState()) + + backend.stateMutex.RLock() + defer backend.stateMutex.RUnlock() + assert.True(t, backend.state.WiFiConnected) + assert.Equal(t, "wlan1", backend.state.WiFiDevice) +}