From 3f66d15af7d5b5367a4fe18ca48950d7000f19b3 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 1 May 2026 09:10:00 -0400 Subject: [PATCH] fix(wifi): check _setup_iptables_redirect return; fix hostapd LED SSID; teardown on exception - Both AP startup paths (hostapd and nmcli) now check the bool returned by _setup_iptables_redirect() and treat False as a hard failure: the hostapd path stops hostapd/dnsmasq and returns an error tuple; the nmcli path brings down and deletes the LEDMatrix-Setup-AP profile and clears the LED message - _enable_ap_mode_hostapd's LED message now calls _validate_ap_config() to get the same sanitized SSID that _create_hostapd_config() uses, so the displayed name always matches the AP actually broadcast by hostapd - _setup_iptables_redirect's outer except block now calls _teardown_iptables_redirect() before returning False so partial iptables/ ip_forward state is always cleaned up on unexpected exceptions; cleanup exceptions are caught and logged separately Co-Authored-By: Claude Sonnet 4.6 --- src/wifi_manager.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/wifi_manager.py b/src/wifi_manager.py index be1906c6..7d1f2389 100644 --- a/src/wifi_manager.py +++ b/src/wifi_manager.py @@ -788,6 +788,10 @@ class WiFiManager: return True except Exception as e: logger.warning(f"Could not set up iptables redirect: {e}") + try: + self._teardown_iptables_redirect() + except Exception as cleanup_e: + logger.warning(f"Cleanup after iptables redirect exception also failed: {cleanup_e}") return False def _teardown_iptables_redirect(self) -> None: @@ -1824,10 +1828,17 @@ class WiFiManager: return False, f"Failed to start dnsmasq: {result.stderr}" # Set up iptables port forwarding (port 80 → 5000) and save ip_forward state - self._setup_iptables_redirect() - + if not self._setup_iptables_redirect(): + logger.error("Captive-portal redirect setup failed; stopping AP services") + subprocess.run(["sudo", "systemctl", "stop", HOSTAPD_SERVICE], + capture_output=True, timeout=10) + subprocess.run(["sudo", "systemctl", "stop", DNSMASQ_SERVICE], + capture_output=True, timeout=10) + return False, "AP started but captive-portal redirect setup failed" + logger.info("AP mode enabled successfully") - ap_ssid = self.config.get("ap_ssid", DEFAULT_AP_SSID) + # Use the validated SSID so the displayed name matches what hostapd broadcast + ap_ssid, _ = self._validate_ap_config() self._show_led_message( f"WiFi Setup\n{ap_ssid}\nNo password\n192.168.4.1:5000", duration=10 ) @@ -1917,7 +1928,14 @@ class WiFiManager: # NM's ipv4.method=shared manages ip_forward automatically, so we only # need to add the iptables port-redirect rules for the captive portal. - self._setup_iptables_redirect() + if not self._setup_iptables_redirect(): + logger.error("Captive-portal redirect setup failed; rolling back AP profile") + subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"], + capture_output=True, timeout=10) + subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"], + capture_output=True, timeout=10) + self._clear_led_message() + return False, "AP started but captive-portal redirect setup failed" # Verify the AP is actually running status = self._get_ap_status_nmcli()