Rewrite entire network package and update wifi page
This commit is contained in:
+89
-18
@@ -28,6 +28,22 @@ const (
|
|||||||
nmDeviceTypeWifi uint32 = 2
|
nmDeviceTypeWifi uint32 = 2
|
||||||
nmDeviceStateActivated uint32 = 100
|
nmDeviceStateActivated uint32 = 100
|
||||||
APFlagsPrivacy uint32 = 0x00000001 // Equivalent to NM_802_11_AP_FLAGS_PRIVACY
|
APFlagsPrivacy uint32 = 0x00000001 // Equivalent to NM_802_11_AP_FLAGS_PRIVACY
|
||||||
|
|
||||||
|
// Device states (from NM spec)
|
||||||
|
nmDeviceStateUnknown uint32 = 0
|
||||||
|
nmDeviceStateUnmanaged uint32 = 10
|
||||||
|
nmDeviceStateUnavailable uint32 = 20
|
||||||
|
nmDeviceStateDisconnected uint32 = 30
|
||||||
|
nmDeviceStateFailed uint32 = 120
|
||||||
|
|
||||||
|
// AP Security Flags (from NM_802_11_AP_SEC_*)
|
||||||
|
APFlagsWpaPsk uint32 = 0x00000100 // WPA-Personal
|
||||||
|
APFlagsWpaEap uint32 = 0x00000200 // WPA-Enterprise
|
||||||
|
APFlagsRsnPsk uint32 = 0x00000100 // WPA2-Personal (same flag as WPA-PSK)
|
||||||
|
APFlagsRsnSae uint32 = 0x00000400 // WPA3-Personal (SAE)
|
||||||
|
APFlagsRsnEap uint32 = 0x00000200 // WPA2-Enterprise (same flag as WPA-EAP)
|
||||||
|
APFlagsRsnOwe uint32 = 0x00000800 // OWE (Opportunistic Wireless Encryption)
|
||||||
|
APFlagsRsnEapSuiteB uint32 = 0x00001000 // WPA3-Enterprise
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrScanAborted is returned when a scan is cancelled via the stop channel.
|
// ErrScanAborted is returned when a scan is cancelled via the stop channel.
|
||||||
@@ -128,7 +144,11 @@ func (m *Manager) FindDevices() error {
|
|||||||
log.Printf("network: Skipping device %s, could not get DeviceType: %v", path, err)
|
log.Printf("network: Skipping device %s, could not get DeviceType: %v", path, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
deviceType, _ := typeVariant.Value().(uint32)
|
deviceType, ok := typeVariant.Value().(uint32)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("network: Skipping device %s, invalid DeviceType", path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var newDevice Device
|
var newDevice Device
|
||||||
switch deviceType {
|
switch deviceType {
|
||||||
@@ -141,10 +161,29 @@ func (m *Manager) FindDevices() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newDevice.Path = path
|
newDevice.Path = path
|
||||||
ifaceVariant, _ := deviceObj.GetProperty(nmDeviceInterface + ".Interface")
|
|
||||||
newDevice.InterfaceName, _ = ifaceVariant.Value().(string)
|
// Safely get Interface property
|
||||||
stateVariant, _ := deviceObj.GetProperty(nmDeviceInterface + ".State")
|
ifaceVariant, err := deviceObj.GetProperty(nmDeviceInterface + ".Interface")
|
||||||
newDevice.State, _ = stateVariant.Value().(uint32)
|
if err != nil {
|
||||||
|
log.Printf("network: Skipping device %s, could not get Interface: %v", path, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if newDevice.InterfaceName, ok = ifaceVariant.Value().(string); !ok {
|
||||||
|
log.Printf("network: Skipping device %s, invalid Interface", path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safely get State property
|
||||||
|
stateVariant, err := deviceObj.GetProperty(nmDeviceInterface + ".State")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("network: Skipping device %s, could not get State: %v", path, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if newDevice.State, ok = stateVariant.Value().(uint32); !ok {
|
||||||
|
log.Printf("network: Skipping device %s, invalid State", path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
m.Devices = append(m.Devices, newDevice)
|
m.Devices = append(m.Devices, newDevice)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -259,8 +298,8 @@ func (m *Manager) scanAccessPoints(apPaths []dbus.ObjectPath) ([]AccessPoint, er
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ssidBytes, _ := props["Ssid"].Value().([]byte)
|
ssidBytes, ok := props["Ssid"].Value().([]byte)
|
||||||
if len(ssidBytes) == 0 {
|
if !ok || len(ssidBytes) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,12 +311,30 @@ func (m *Manager) scanAccessPoints(apPaths []dbus.ObjectPath) ([]AccessPoint, er
|
|||||||
|
|
||||||
isProtected := (flags&APFlagsPrivacy != 0) || (wpaFlags != 0) || (rsnFlags != 0)
|
isProtected := (flags&APFlagsPrivacy != 0) || (wpaFlags != 0) || (rsnFlags != 0)
|
||||||
|
|
||||||
// Determine the key management type
|
// Determine key management type
|
||||||
var keyMgmt string
|
var keyMgmt string
|
||||||
if wpaFlags != 0 {
|
if !isProtected {
|
||||||
keyMgmt = "wpa-psk"
|
keyMgmt = "none"
|
||||||
|
} else if wpaFlags != 0 {
|
||||||
|
// WPA (not WPA2/WPA3)
|
||||||
|
if wpaFlags&APFlagsWpaPsk != 0 {
|
||||||
|
keyMgmt = "wpa-psk"
|
||||||
|
} else if wpaFlags&APFlagsWpaEap != 0 {
|
||||||
|
keyMgmt = "wpa-eap"
|
||||||
|
} else {
|
||||||
|
keyMgmt = "wpa-psk" // Fallback
|
||||||
|
}
|
||||||
} else if rsnFlags != 0 {
|
} else if rsnFlags != 0 {
|
||||||
keyMgmt = "wpa-psk"
|
// WPA2 or WPA3 (RSN)
|
||||||
|
if rsnFlags&APFlagsRsnSae != 0 {
|
||||||
|
keyMgmt = "sae" // WPA3-Personal
|
||||||
|
} else if rsnFlags&APFlagsRsnEapSuiteB != 0 {
|
||||||
|
keyMgmt = "eap-suite-b-192" // WPA3-Enterprise
|
||||||
|
} else if rsnFlags&APFlagsRsnEap != 0 {
|
||||||
|
keyMgmt = "wpa-eap" // WPA2-Enterprise
|
||||||
|
} else {
|
||||||
|
keyMgmt = "wpa-psk" // WPA2-Personal (default for RSN)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
keyMgmt = "none"
|
keyMgmt = "none"
|
||||||
}
|
}
|
||||||
@@ -313,6 +370,12 @@ func (m *Manager) Connect(wifiDevice Device, ap AccessPoint, passphrase string)
|
|||||||
return fmt.Errorf("cannot connect: provided device is not a Wi-Fi device")
|
return fmt.Errorf("cannot connect: provided device is not a Wi-Fi device")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wifiDevice.State == nmDeviceStateFailed ||
|
||||||
|
wifiDevice.State == nmDeviceStateUnmanaged ||
|
||||||
|
wifiDevice.State == nmDeviceStateUnavailable {
|
||||||
|
return fmt.Errorf("cannot connect: device is in an error state (state=%d)", wifiDevice.State)
|
||||||
|
}
|
||||||
|
|
||||||
settings := map[string]map[string]dbus.Variant{
|
settings := map[string]map[string]dbus.Variant{
|
||||||
"connection": {
|
"connection": {
|
||||||
"type": dbus.MakeVariant("802-11-wireless"),
|
"type": dbus.MakeVariant("802-11-wireless"),
|
||||||
@@ -365,14 +428,22 @@ func (m *Manager) Connect(wifiDevice Device, ap AccessPoint, passphrase string)
|
|||||||
|
|
||||||
// pingTest with a short timeout to prevent the UI loop from hanging
|
// pingTest with a short timeout to prevent the UI loop from hanging
|
||||||
func pingTest() bool {
|
func pingTest() bool {
|
||||||
// Use a dialer with a timeout instead of LookupHost which can hang
|
targets := []string{
|
||||||
timeout := 2 * time.Second
|
"1.1.1.1:53", // Cloudflare DNS
|
||||||
conn, err := net.DialTimeout("tcp", "8.8.8.8:53", timeout)
|
"8.8.8.8:53", // Google DNS
|
||||||
if err != nil {
|
"9.9.9.9:53", // Quad9 DNS
|
||||||
return false
|
"149.112.112.112:53", // Quad9 Alternate
|
||||||
}
|
}
|
||||||
conn.Close()
|
timeout := 2 * time.Second
|
||||||
return true
|
|
||||||
|
for _, target := range targets {
|
||||||
|
conn, err := net.DialTimeout("tcp", target, timeout)
|
||||||
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAllProperties is a helper to fetch all properties for a D-Bus object interface.
|
// getAllProperties is a helper to fetch all properties for a D-Bus object interface.
|
||||||
|
|||||||
@@ -91,13 +91,10 @@ func (p *WiFiSetupPage) Init(ctx *PageCtx) error {
|
|||||||
|
|
||||||
// Find Wi-Fi device
|
// Find Wi-Fi device
|
||||||
if err := p.networkManager.FindDevices(); err != nil {
|
if err := p.networkManager.FindDevices(); err != nil {
|
||||||
}
|
// Clean up before returning error
|
||||||
for _, dev := range p.networkManager.Devices {
|
p.networkManager.Close()
|
||||||
if dev.Type == network.TypeWifi {
|
p.networkManager = nil
|
||||||
d := dev
|
return fmt.Errorf("failed to find network devices: %w. Try rebooting the computer. If this is your 3rd reboot, call for help", err)
|
||||||
p.wifiDevice = &d
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create UI elements
|
// Create UI elements
|
||||||
@@ -161,17 +158,11 @@ func (p *WiFiSetupPage) startScan() {
|
|||||||
// HandleEvent processes user input.
|
// HandleEvent processes user input.
|
||||||
func (p *WiFiSetupPage) HandleEvent(event *sdl.Event) error {
|
func (p *WiFiSetupPage) HandleEvent(event *sdl.Event) error {
|
||||||
switch e := (*event).(type) {
|
switch e := (*event).(type) {
|
||||||
|
|
||||||
case *sdl.TextInputEvent:
|
case *sdl.TextInputEvent:
|
||||||
if p.isEnteringPassword {
|
if p.isEnteringPassword {
|
||||||
// If we get a TextInputEvent, the system supports high-level input.
|
p.passwordInput += e.GetText() // Always append text
|
||||||
// Mark it supported so we don't double-type from KeyboardEvents.
|
p.textInputSupported = true // Mark as supported
|
||||||
if !p.textInputSupported {
|
p.updatePasswordTexture()
|
||||||
p.textInputSupported = true
|
|
||||||
} else {
|
|
||||||
p.passwordInput += e.GetText()
|
|
||||||
p.updatePasswordTexture()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case *sdl.KeyboardEvent:
|
case *sdl.KeyboardEvent:
|
||||||
@@ -180,13 +171,11 @@ func (p *WiFiSetupPage) HandleEvent(event *sdl.Event) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.isEnteringPassword {
|
if p.isEnteringPassword {
|
||||||
// Pass the Modifiers (Shift/Caps) to the handler
|
|
||||||
p.handlePasswordInput(e.Keysym.Sym, e.Keysym.Mod)
|
p.handlePasswordInput(e.Keysym.Sym, e.Keysym.Mod)
|
||||||
} else {
|
} else {
|
||||||
p.handleNetworkSelection(e.Keysym.Sym)
|
p.handleNetworkSelection(e.Keysym.Sym)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +312,7 @@ func (p *WiFiSetupPage) handleNetworkSelection(sym sdl.Keycode) {
|
|||||||
case sdl.K_RETURN:
|
case sdl.K_RETURN:
|
||||||
if len(p.accessPoints) > 0 && p.selectedIndex < len(p.accessPoints) {
|
if len(p.accessPoints) > 0 && p.selectedIndex < len(p.accessPoints) {
|
||||||
p.selectedAP = &p.accessPoints[p.selectedIndex].AP
|
p.selectedAP = &p.accessPoints[p.selectedIndex].AP
|
||||||
p.pendingSSID = p.selectedAP.SSID
|
p.pendingSSID = p.selectedAP.SSID // Set for ALL networks (protected or not)
|
||||||
p.connectionError = ""
|
p.connectionError = ""
|
||||||
if p.selectedAP.IsProtected {
|
if p.selectedAP.IsProtected {
|
||||||
p.isEnteringPassword = true
|
p.isEnteringPassword = true
|
||||||
@@ -338,7 +327,7 @@ func (p *WiFiSetupPage) handleNetworkSelection(sym sdl.Keycode) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
p.isConnecting = false
|
p.isConnecting = false
|
||||||
p.pendingSSID = ""
|
p.pendingSSID = ""
|
||||||
p.connectionError = "Failed to initiate connection"
|
p.connectionError = fmt.Sprintf("Failed to connect: %s", err.Error()) // Include actual error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,18 +373,17 @@ func (p *WiFiSetupPage) Update(dt float32) error {
|
|||||||
|
|
||||||
// handleConnectionStatusUpdate CHECKS0 if connection succeeded or failed
|
// handleConnectionStatusUpdate CHECKS0 if connection succeeded or failed
|
||||||
func (p *WiFiSetupPage) handleConnectionStatusUpdate(status *network.ConnectionStatus) {
|
func (p *WiFiSetupPage) handleConnectionStatusUpdate(status *network.ConnectionStatus) {
|
||||||
if !p.isConnecting {
|
if !p.isConnecting || p.pendingSSID == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// milestone 1: We are associated with an AP (even if internet is still pending)
|
// Only consider it successful if we're connected to the EXACT network we tried to join
|
||||||
isConnected := status.StatusCode == network.StatusWifiConnectedInternetUp ||
|
isConnectedToPending := status.StatusCode == network.StatusWifiConnectedInternetUp ||
|
||||||
status.StatusCode == network.StatusWifiConnectedNoInternet
|
status.StatusCode == network.StatusWifiConnectedNoInternet
|
||||||
|
|
||||||
if isConnected {
|
if isConnectedToPending {
|
||||||
activeSSID := p.getActiveSSID()
|
activeSSID := p.getActiveSSID()
|
||||||
// If we see our SSID, OR if we're connected to anything while trying, call it a win.
|
if activeSSID == p.pendingSSID { // ONLY accept if it's the network we tried
|
||||||
if activeSSID == p.pendingSSID || activeSSID != "" {
|
|
||||||
logger.Info("UI synced: Connected to %s", activeSSID)
|
logger.Info("UI synced: Connected to %s", activeSSID)
|
||||||
p.isConnecting = false
|
p.isConnecting = false
|
||||||
p.pendingSSID = ""
|
p.pendingSSID = ""
|
||||||
@@ -405,14 +393,12 @@ func (p *WiFiSetupPage) handleConnectionStatusUpdate(status *network.ConnectionS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// milestone 2: Handle the "Not Connected" state during the handshake
|
// Handle failure: If we've been trying for too long, show error
|
||||||
if status.StatusCode == network.StatusWifiAvailableNotConnected {
|
if status.StatusCode == network.StatusWifiAvailableNotConnected {
|
||||||
// INCREASE THIS: 5 seconds is way too aggressive.
|
|
||||||
// Give it at least 20 seconds before assuming the password was wrong.
|
|
||||||
if time.Since(p.connectionAttemptTime) > 20*time.Second {
|
if time.Since(p.connectionAttemptTime) > 20*time.Second {
|
||||||
if time.Since(p.connectionAttemptTime) > 15*time.Second {
|
p.isConnecting = false
|
||||||
p.isConnecting = false
|
p.connectionError = "Connection failed - Check password or signal"
|
||||||
p.connectionError = "Connection failed - Check password or signal"
|
if p.selectedAP != nil && p.selectedAP.IsProtected {
|
||||||
p.isEnteringPassword = true
|
p.isEnteringPassword = true
|
||||||
p.enterPasswordMode()
|
p.enterPasswordMode()
|
||||||
p.updatePasswordErrorTexture()
|
p.updatePasswordErrorTexture()
|
||||||
@@ -553,6 +539,13 @@ func (p *WiFiSetupPage) updateConnectionStatusItem() {
|
|||||||
|
|
||||||
// buildNetworkUIList creates the renderable textures for the list of discovered networks.
|
// buildNetworkUIList creates the renderable textures for the list of discovered networks.
|
||||||
func (p *WiFiSetupPage) buildNetworkUIList(aps []network.AccessPoint) {
|
func (p *WiFiSetupPage) buildNetworkUIList(aps []network.AccessPoint) {
|
||||||
|
// Delete old textures to prevent memory leaks
|
||||||
|
for _, apItem := range p.accessPoints {
|
||||||
|
if apItem.Item.ID != 0 {
|
||||||
|
gl.DeleteTextures(1, &apItem.Item.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the currently active Wi-Fi SSID
|
// Get the currently active Wi-Fi SSID
|
||||||
activeSSID := p.getActiveSSID()
|
activeSSID := p.getActiveSSID()
|
||||||
p.activeSSID = activeSSID
|
p.activeSSID = activeSSID
|
||||||
|
|||||||
Reference in New Issue
Block a user