From 81df0946be0b6e8fe5243a1b4b49f985e68584e8 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Fri, 18 Sep 2026 15:57:05 -0700 Subject: [PATCH] native: harden wpa_supplicant restart so reconnects don't sit dead 60s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A connect right after another network came up could fork a new wpa_supplicant before the killed one released wlan0 and its ctrl socket; the new daemon then failed to start and wpa_cli reported an empty state for the whole 60s poll (seen on a CULTUREHUB LA reconnect after Guest). Now waits 300ms after killall, then confirms the ctrl socket appears and restarts once if not. The spaced SSID itself was fine — quoted in wpa.conf, kept whole by the scan parser, never shell-interpolated. Co-Authored-By: Claude Opus 4.8 --- fedac/native/src/wifi.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/fedac/native/src/wifi.c b/fedac/native/src/wifi.c index 3af1d5b565..c40b672902 100644 --- a/fedac/native/src/wifi.c +++ b/fedac/native/src/wifi.c @@ -244,6 +244,7 @@ static void wifi_do_connect(ACWifi *wifi, const char *ssid, const char *password wifi->dhcp_pid = 0; } run_cmd("killall wpa_supplicant 2>/dev/null; killall dhclient 2>/dev/null"); + usleep(300000); // let a just-killed wpa_supplicant release wlan0 + its ctrl socket // Write wpa_supplicant config FILE *fp = fopen("/tmp/wpa.conf", "w"); @@ -296,6 +297,47 @@ static void wifi_do_connect(ACWifi *wifi, const char *ssid, const char *password wifi->wpa_pid = pid; waitpid(pid, NULL, 0); // Wait for wpa_supplicant to daemonize (-B) + // Confirm the daemon actually came up: -B forks and the parent exits, so a + // failed start (interface still busy from the previous connect, exec not + // found) leaves nothing listening and wpa_cli reports an empty state for + // the whole 60s poll. Wait briefly for the ctrl socket, retrying the start + // once, before committing to the poll loop. Bug seen on CULTUREHUB LA + // reconnects right after another network came up. + { + char sock_path[128]; + snprintf(sock_path, sizeof(sock_path), + "/var/run/wpa_supplicant/%s", wifi->iface); + int up = 0; + for (int attempt = 0; attempt < 2 && !up; attempt++) { + for (int w = 0; w < 20; w++) { // up to ~1s + if (access(sock_path, F_OK) == 0) { up = 1; break; } + usleep(50000); + } + if (up) break; + wifi_log(wifi, "wpa_supplicant didn't come up, restarting (attempt %d)", attempt + 1); + run_cmd("killall wpa_supplicant 2>/dev/null"); + usleep(300000); + unlink(sock_path); + pid_t rpid = fork(); + if (rpid == 0) { + const char *wpa_paths[] = { + "/bin/wpa_supplicant", "/usr/bin/wpa_supplicant", + "/usr/sbin/wpa_supplicant", "/sbin/wpa_supplicant", NULL + }; + for (int i = 0; wpa_paths[i]; i++) + if (file_exists(wpa_paths[i])) + execl(wpa_paths[i], "wpa_supplicant", + "-i", wifi->iface, "-c", "/tmp/wpa.conf", + "-B", "-P", "/tmp/wpa.pid", NULL); + _exit(1); + } + wifi->wpa_pid = rpid; + waitpid(rpid, NULL, 0); + } + if (!up) + wifi_log(wifi, "wpa_supplicant not responding for '%s' — will poll anyway", ssid); + } + pthread_mutex_lock(&wifi->lock); strncpy(wifi->connected_ssid, ssid, WIFI_SSID_MAX - 1); pthread_mutex_unlock(&wifi->lock); -- 2.51.2