wpa_supplicant: Reuse existing networks and preserve saved ones on connect

Connect() called AddNetwork unconditionally, creating duplicate entries for
the same SSID, and SelectNetwork's side-effect of disabling all other
networks was being persisted by SaveConfig — making previously saved
networks appear erased. Disconnect() also removed the current network from
the config. Now reuse an existing network entry when the SSID matches,
re-enable other networks after SelectNetwork, and keep entries on
disconnect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
nemunaire 2026-05-01 18:25:30 +08:00
commit 77370eff19
3 changed files with 102 additions and 23 deletions

View file

@ -152,35 +152,69 @@ func (b *WPABackend) IsScanning() (bool, error) {
// Connect connects to a WiFi network
func (b *WPABackend) Connect(ssid, password string) error {
// Create network configuration
config := make(map[string]interface{})
config["ssid"] = ssid // Raw SSID string, no quotes
if password != "" {
// For WPA/WPA2-PSK networks
config["psk"] = password // Raw password string, no quotes
} else {
// For open networks
config["key_mgmt"] = "NONE"
}
// Add network
networkPath, err := b.iface.AddNetwork(config)
// Look up existing network with the same SSID to avoid creating duplicates
existingNetworks, err := b.iface.GetNetworks()
if err != nil {
return fmt.Errorf("failed to add network: %v", err)
return fmt.Errorf("failed to list configured networks: %v", err)
}
// Store current network path for cleanup
var networkPath dbus.ObjectPath
createdNew := false
for _, p := range existingNetworks {
net := NewNetwork(b.conn, p)
netSSID, err := net.GetSSID()
if err != nil || netSSID != ssid {
continue
}
networkPath = p
break
}
if networkPath == "" {
// Create network configuration
config := make(map[string]interface{})
config["ssid"] = ssid // Raw SSID string, no quotes
if password != "" {
// For WPA/WPA2-PSK networks
config["psk"] = password // Raw password string, no quotes
} else {
// For open networks
config["key_mgmt"] = "NONE"
}
networkPath, err = b.iface.AddNetwork(config)
if err != nil {
return fmt.Errorf("failed to add network: %v", err)
}
createdNew = true
}
// Store current network path
b.currentNetwork = networkPath
// Select (connect to) the network
// Select (connect to) the network. Note: SelectNetwork disables every
// other configured network as a side-effect.
err = b.iface.SelectNetwork(networkPath)
if err != nil {
// Clean up network on failure
b.iface.RemoveNetwork(networkPath)
if createdNew {
b.iface.RemoveNetwork(networkPath)
}
return fmt.Errorf("failed to select network: %v", err)
}
// Re-enable previously configured networks so SelectNetwork's side-effect
// doesn't mark them all as disabled in the persisted config.
for _, p := range existingNetworks {
if p == networkPath {
continue
}
if err := b.iface.EnableNetwork(p); err != nil {
fmt.Printf("Warning: failed to re-enable network %s: %v\n", p, err)
}
}
// Save the configuration to persist it across reboots
if err := b.iface.SaveConfig(); err != nil {
// Log warning but don't fail - connection still works
@ -197,11 +231,7 @@ func (b *WPABackend) Disconnect() error {
return fmt.Errorf("failed to disconnect: %v", err)
}
// Remove the network configuration if we have one
if b.currentNetwork != "" && b.currentNetwork != "/" {
b.iface.RemoveNetwork(b.currentNetwork)
b.currentNetwork = ""
}
b.currentNetwork = ""
return nil
}