/* test_wifi_connect.c — WiFi 设置页 bug1/bug2/bug4 宿主桩测试(2026-09-15)。 * * 通过 #include meow_netmgrd.c 直接驱动 static 的 wifi_connect_ex(),绕过 daemon 的 * SO_PEERCRED 系统身份鉴权(宿主 CLI=CALL_OTHER 写级必拒,无法经 IPC 测连接路径)。 * 桩 wpa_cli 由本程序写入临时目录;控制文件(status_mode/list/save_fail_once)决定 * status 序列 / list_networks 原文 / save_config 是否首败,调用日志写入 /log 供断言。 * * 编译:cc -Wall -Wextra -I../meow_launcherd test_wifi_connect.c -o test_wifi_connect */ #define _GNU_SOURCE #define main meow_netmgrd_main #include "meow_netmgrd.c" #undef main #include static char g_dir[128]; static int g_pass = 0, g_fail = 0; static void ck(const char *name, int cond, const char *detail) { if (cond) { g_pass++; printf("PASS %s\n", name); } else { g_fail++; printf("FAIL %s: %s\n", name, detail ? detail : ""); } fflush(stdout); } static void putf(const char *name, const char *fmt, ...) { char path[192], body[512]; va_list ap; va_start(ap, fmt); vsnprintf(body, sizeof body, fmt, ap); va_end(ap); snprintf(path, sizeof path, "%s/%s", g_dir, name); FILE *f = fopen(path, "w"); if (f) { fputs(body, f); fclose(f); } } static int log_has(const char *needle) { char path[192], buf[8192]; snprintf(path, sizeof path, "%s/log", g_dir); FILE *f = fopen(path, "r"); if (!f) return 0; size_t n = fread(buf, 1, sizeof buf - 1, f); fclose(f); buf[n] = 0; return strstr(buf, needle) != NULL; } static void reset_log(void) { char path[192]; snprintf(path, sizeof path, "%s/log", g_dir); FILE *f = fopen(path, "w"); if (f) fclose(f); } static void write_stub(void) { char path[192]; snprintf(path, sizeof path, "%s/wpa_cli", g_dir); FILE *f = fopen(path, "w"); if (!f) { fprintf(stderr, "stub open fail\n"); exit(2); } fputs( "#!/bin/sh\n" "D=\"${MN_WIFI_DIR:-/tmp}\"\n" "echo \"$@\" >> \"$D/log\"\n" "case \"$1\" in\n" " status)\n" " m=$(cat \"$D/status_mode\" 2>/dev/null || echo completed)\n" " if [ \"$m\" = \"associating\" ]; then\n" " echo \"wpa_state=ASSOCIATING\"; echo \"ssid=MyWiFi\"\n" " else\n" " echo \"wpa_state=COMPLETED\"; echo \"ssid=MyWiFi\"\n" " echo \"ip_address=10.78.193.50\"; echo \"signal=-45\"\n" " fi\n" " ;;\n" " list_networks)\n" " if [ -f \"$D/list\" ]; then cat \"$D/list\"\n" " else printf 'network id / ssid / bssid / flags\\n0\\tMyWiFi\\tany\\t[CURRENT]\\n'\n" " fi\n" " ;;\n" " add_network) echo 1 ;;\n" " set_network) echo OK ;;\n" " enable_network) echo OK ;;\n" " select_network) echo OK ;;\n" " disconnect) echo OK ;;\n" " save_config)\n" " if [ -f \"$D/save_fail_once\" ]; then rm -f \"$D/save_fail_once\"; echo FAIL; else echo OK; fi\n" " ;;\n" " set) echo OK ;;\n" " remove_network) echo OK ;;\n" " *) echo OK ;;\n" "esac\n" "exit 0\n", f); fclose(f); chmod(path, 0755); } int main(void) { snprintf(g_dir, sizeof g_dir, "/tmp/mnwifi.XXXXXX"); if (!mkdtemp(g_dir)) { fprintf(stderr, "mkdtemp fail\n"); return 2; } write_stub(); setenv("MN_WIFI_DIR", g_dir, 1); g_mode_meow = 1; g_connect_wait_ms = 400; g_connecth_wait_ms = 400; { char p[192]; snprintf(p, sizeof p, "%s/wpa_cli", g_dir); g_wpa_cli = p; } ctl_result_t r; /* ① 成功:命中既有 id=0 + 带新 psk → 更新凭据,等待 COMPLETED,成功报 ip。 */ putf("status_mode", "completed"); ctl_reset(&r, MEOW_OK); reset_log(); wifi_connect_ex("MyWiFi,secret", &r, 0); ck("connect-success code", r.code == MEOW_OK, r.text); ck("connect-success text ip", strstr(r.text, "已连接") && strstr(r.text, "ip=10.78.193.50"), r.text); ck("connect-success psk update", log_has("set_network 0 psk"), ""); ck("connect-success enable all", log_has("enable_network all"), ""); /* ② 错误密码/不在范围:status 恒 ASSOCIATING → 超时失败,新建 id 被回收。 */ putf("status_mode", "associating"); reset_log(); ctl_reset(&r, MEOW_OK); wifi_connect_ex("OtherWiFi", &r, 0); ck("connect-timeout code", r.code == MEOW_ERR_NODEV, r.text); ck("connect-timeout text", strstr(r.text, "连接失败") != NULL, r.text); ck("connect-timeout remove new", log_has("remove_network 1"), ""); /* ③ 中文 SSID \xNN 还原匹配:list_networks 原文转义,输入 UTF-8 名 → 命中 id=0 不新建。 */ putf("status_mode", "completed"); putf("list", "network id / ssid / bssid / flags\n0\t\\xe5\\xa4\\xa9\\xe5\\xa4\\xa9\tany\t[CURRENT]\n"); reset_log(); ctl_reset(&r, MEOW_OK); wifi_connect_ex("天天", &r, 0); ck("connect-escape match", r.code == MEOW_OK, r.text); ck("connect-escape no add", !log_has("add_network"), ""); /* ④ connecth:隐藏网络命中既有 id → 追加 scan_ssid 1。 */ putf("status_mode", "completed"); putf("list", "network id / ssid / bssid / flags\n0\tMyWiFi\tany\t[CURRENT]\n"); reset_log(); ctl_reset(&r, MEOW_OK); wifi_connect_ex("MyWiFi", &r, 1); ck("connecth scan_ssid", r.code == MEOW_OK && log_has("set_network 0 scan_ssid 1"), r.text); /* ⑤ save_config 首败 → set update_config 1 重试 → 持久化成功。 */ putf("status_mode", "completed"); putf("list", "network id / ssid / bssid / flags\n0\tMyWiFi\tany\t[CURRENT]\n"); putf("save_fail_once", "1"); reset_log(); ctl_reset(&r, MEOW_OK); wifi_connect_ex("MyWiFi", &r, 0); ck("save-config retry", r.code == MEOW_OK && !strstr(r.text, "记录未持久化"), r.text); ck("save-config set update_config", log_has("set update_config 1"), ""); printf("==============================\nPASS=%d FAIL=%d\n", g_pass, g_fail); return g_fail == 0 ? 0 : 1; }