随着AI智能体的发展,skill成为智能体必不可少的一部分。之前写代码,讲究是如何让代码模块化才好复用。现在可能就得考虑如何用skill来实现代码复用。上一篇讲了在嵌入式linux下如何处理WIFI连接更省内存实现的思路,这一篇讲一下这种处理方法的skill。

  我这里是使用open code来让它根据我提供的代码,来生成一个用于C编程的WIFI连接处理的skill

image

 等了一会,他就给我生成了一个embedded-wifi-manager文件夹,包含SKILL.md文档

---
name: embedded-linux-wifi-manager
description: 用于在资源受限的嵌入式 Linux 系统中,通过 C 语言直接操作内核接口(ioctl/socket)管理 Wi-Fi 连接、状态监控及自动恢复的技能。
version: 1.0.0
author: dearlong_00
---

# 🛠️ 工业级嵌入式 Linux WiFi 管理 Skill

你是一个嵌入式 Linux 系统架构师。当用户需要为低功耗、低内存的嵌入式设备(如 IPCamera、IoT 终端)开发 Wi-Fi 功能时,请使用此 Skill。

## 核心原则 (Core Principles)

1.  **零 Shell 依赖 (Zero Shell Overhead):** 
    -   **禁止**使用 `system()` 调用 shell 脚本。
    -   **必须**使用 `vfork()` + `exec` 或直接使用内核 API(ioctl, socket)。
    -   **必须**包含 `run_cmd`, `run_cmd_direct`, `run_cmd_redirect` 等轻量级执行函数。

2.  **内存安全优先 (Memory Safety First):**
    -   在执行任何网络操作前,必须调用 `check_system_memory_ok()` 检查可用内存。
    -   如果内存低于阈值(默认 600KB),跳过操作或进行分级恢复。

3.  **分级恢复机制 (Graded Recovery):**
    -   **P0 (轻量级):** 重启 DHCP 客户端 (`udhcpc`)。
    -   **P1 (中等级):** 重启网络接口 (ioctl SIOCSIFFLAGS)。
    -   **P2 (重量级):** 重载驱动模块 (rmmod/insmod) 或重启 `wpa_supplicant`。

4.  **直接内核交互 (Direct Kernel Interaction):**
    -   获取信号强度:使用 `ioctl(SIOCGIWSTATS)` 替代 `iwconfig`。
    -   获取 IP:使用 `ioctl(SIOCGIFADDR)`。
    -   Ping 检测:使用 Raw Socket 手动构造 ICMP 包,而非调用系统 `ping` 命令。

## 关键组件实现规范

### 1. 进程与命令执行 (Process & Command)
生成轻量级进程执行函数,优先使用 `vfork` 以减少内存拷贝。

### 2. WiFi 状态机 (State Machine)
实现一个包含以下状态的监控循环:
-   **DISCONNECTED:** 尝试轻量级重连 (DHCP/Interface)。
-   **AUTHENTICATED_NO_IP:** 检测到已认证但无 IP,触发 DHCP 修复。
-   **COMPLETED:** 已连接,检查网关和公网连通性。

### 3. 网络连通性检测 (Connectivity Check)
-   **网关检测:** 使用 `quick_ping` (Raw Socket) 或 TCP 连接网关 80/53 端口。
-   **公网检测:** 尝试连接 `8.8.8.8:53` (DNS 端口,通常不被防火墙拦截)。

## 代码生成逻辑 (Code Generation Logic)

当用户请求生成 "连接 Wi-Fi""Wi-Fi 守护进程" 时,请输出包含以下核心逻辑的 C 代码:

### A. 内存保护检查 (Memory Guard)
// 生成此函数的逻辑:在 reset_network_full_optimized 或 restart_dhcp 中调用
if (!check_system_memory_ok(MIN_MEM_KB_FOR_OPERATION)) {
    // 记录日志并跳过重置
    return;
}
### B. 信号强度获取 (Signal Strength)
// 生成此逻辑:替代解析 iwlist 输出
int wifi_get_ssid_signal_strength(int *rssi) {
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    struct iwreq ifr;
    // ... 初始化 ifr ...
    if (ioctl(fd, SIOCGIWSTATS, &ifr) == 0) {
        // 解析 stats.qual.level
        *rssi = (int8_t)stats.qual.level; // 或转换公式
    }
}
### C. 分级重置逻辑 (Graded Reset Logic)
请根据失败次数生成对应的恢复策略:

失败计数器                阈值 (示例)    操作 (Action)
consecutive_dhcp_failures    3    restart_dhcp_optimized()
consecutive_dhcp_failures    10    reset_network_full_optimized() (重载驱动)
consecutive_gateway_failures    3    检查网关是否可达,否则重启接口

### D. 完整的 Connect 流程
生成代码时,必须包含以下步骤:
写配置: 生成 wpa_supplicant.conf (包含 ssid, psk, proto)。
杀进程: 安全终止旧的 wpa_supplicant 和 udhcpc。
启模块: 必要时加载驱动模块 (insmod)。
启服务: 启动 wpa_supplicant (后台模式 -B)。
获取 IP: 启动 udhcpc。

#### E. 线程主循环 (wifi_proc)
生成一个后台线程 wifi_proc,逻辑如下:
while(1) {
    // 1. 内存检查
    if (mem < MIN_MEM_KB_CRITICAL) sleep(10); 
    
    // 2. 状态检查
    int status = wifi_check_connect_state(); 
    
    // 3. NTP 校时 (如果连接成功)
    if (status) wifi_ntp_sync_if_needed();
    
    // 4. 网络连通性检查
    if (!check_gateway_connect()) handle_gateway_loss();
    
    sleep(WIFI_PROC_SLEEP_INTERVAL); // 例如 5秒
}

##约束与常量 (Constraints)
在生成代码时,请使用以下默认常量配置(可根据目标平台微调):
内存阈值: MIN_MEM_KB_FOR_OPERATION = 600 (KB)
重试阈值: DHCP_RETRY_THRESHOLD = 8
重置阈值: FULL_RESET_THRESHOLD = 10
网络接口: HW_NAME = "wlan0"
DHCP 客户端: udhcpc

##示例
用户输入:
请为我的嵌入式 Linux 设备生成一个 Wi-Fi 管理模块,要求能自动重连,并且在内存不足时不要崩溃。
你的回应:
你将生成一个包含 run_cmd, wifi_connect_wifi, wifi_proc 等函数的 C 源文件。代码将严格遵循上述“核心原则”,使用 vfork 启动进程,并在每次重置前检查内存。

 

在workbuddy中,添加这个技能,然后对他说“请使用 `embedded-linux-wifi-manager` Skill,为我生成一个针对 RTL8189FTV 芯片的 Wi-Fi 配置代码”,他就开始工作了

 

image

 生成的代码如下:

/**
 * @file    wifi_rtl8189ftv.c
 * @brief   RTL8189FTV Wi-Fi 管理模块实现
 *
 * 核心设计原则:
 *   1. 零 system() shell 调用 —— 全部使用 vfork()+exec 或 ioctl
 *   2. 内存保护优先 —— 每次重置前检查可用内存
 *   3. 分级恢复 —— P0(DHCP) → P1(接口) → P2(驱动重载)
 *   4. 直接内核交互 —— ioctl(SIOCGIWSTATS) 获取信号强度
 *
 * 编译示例:
 *   arm-linux-gnueabihf-gcc -O2 -Wall \
 *       -I. wifi_rtl8189ftv.c -o wifi_mgr -lpthread
 */

#include "wifi_rtl8189ftv.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <stdarg.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <arpa/inet.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <linux/wireless.h>

/* =========================================================
 * 内部全局状态
 * ========================================================= */

static wifi_config_t  g_wifi_cfg;          /* 当前连接配置 */
static wifi_stats_t   g_wifi_stats;        /* 运行统计信息 */
static pthread_t      g_wifi_thread;       /* 守护线程 */
static volatile int   g_wifi_proc_running; /* 线程运行标志 */
static pthread_mutex_t g_stats_mutex = PTHREAD_MUTEX_INITIALIZER;
static time_t         g_last_ntp_sync;     /* 上次 NTP 同步时间戳 */

/* =========================================================
 * 日志宏(可替换为项目日志框架)
 * ========================================================= */

#define LOG_TAG  "wifi_rtl8189ftv"
#define LOGI(fmt, ...) fprintf(stdout, "[%s][I] " fmt "\n", LOG_TAG, ##__VA_ARGS__)
#define LOGE(fmt, ...) fprintf(stderr, "[%s][E] " fmt "\n", LOG_TAG, ##__VA_ARGS__)
#define LOGW(fmt, ...) fprintf(stdout, "[%s][W] " fmt "\n", LOG_TAG, ##__VA_ARGS__)

/* =========================================================
 * Section 1: 进程执行(vfork + exec,零 shell)
 * ========================================================= */

/**
 * @brief  使用 vfork()+execv 执行命令并等待退出(无超时)
 * @return 子进程退出码,失败返回 -1
 */
int run_cmd(const char *path, char *const argv[]) {
    pid_t pid = vfork();
    if (pid < 0) {
        LOGE("vfork failed: %s", strerror(errno));
        return -1;
    }
    if (pid == 0) {
        /* 子进程:重定向 stdout/stderr 到 /dev/null 避免日志污染 */
        int devnull = open("/dev/null", O_WRONLY);
        if (devnull >= 0) {
            dup2(devnull, STDOUT_FILENO);
            dup2(devnull, STDERR_FILENO);
            close(devnull);
        }
        execv(path, argv);
        _exit(127); /* exec 失败 */
    }
    int status = 0;
    waitpid(pid, &status, 0);
    return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}

/**
 * @brief  执行命令,带超时(秒)。超时后 SIGKILL 子进程。
 * @return 子进程退出码;超时返回 -2;失败返回 -1
 */
int run_cmd_timeout(const char *path, char *const argv[], int timeout_sec) {
    pid_t pid = vfork();
    if (pid < 0) return -1;
    if (pid == 0) {
        int devnull = open("/dev/null", O_WRONLY);
        if (devnull >= 0) {
            dup2(devnull, STDOUT_FILENO);
            dup2(devnull, STDERR_FILENO);
            close(devnull);
        }
        execv(path, argv);
        _exit(127);
    }

    time_t deadline = time(NULL) + timeout_sec;
    while (1) {
        int status = 0;
        pid_t ret = waitpid(pid, &status, WNOHANG);
        if (ret == pid) {
            return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
        }
        if (time(NULL) >= deadline) {
            kill(pid, SIGKILL);
            waitpid(pid, NULL, 0);
            LOGW("run_cmd_timeout: [%s] timed out after %ds", path, timeout_sec);
            return -2;
        }
        usleep(200000); /* 200ms 轮询 */
    }
}

/**
 * @brief  执行命令,将 stdout 重定向到文件
 * @return 子进程退出码,失败返回 -1
 */
int run_cmd_redirect(const char *path, char *const argv[], const char *out_file) {
    pid_t pid = vfork();
    if (pid < 0) return -1;
    if (pid == 0) {
        int fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd >= 0) {
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
            close(fd);
        }
        execv(path, argv);
        _exit(127);
    }
    int status = 0;
    waitpid(pid, &status, 0);
    return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}

/**
 * @brief  通过 PID 文件终止进程
 */
void kill_process_by_pidfile(const char *pid_file) {
    FILE *fp = fopen(pid_file, "r");
    if (!fp) return;
    int pid = 0;
    fscanf(fp, "%d", &pid);
    fclose(fp);
    if (pid > 1) {
        kill(pid, SIGTERM);
        usleep(300000);
        kill(pid, SIGKILL); /* 确保杀死 */
    }
    unlink(pid_file);
}

/**
 * @brief  通过进程名终止所有同名进程(使用 killall 路径,无 shell)
 */
void kill_process_by_name(const char *name) {
    char *argv[] = { (char*)"/usr/bin/killall", "-9", (char*)name, NULL };
    run_cmd("/usr/bin/killall", argv);
}

/* =========================================================
 * Section 2: 内存保护检查
 * ========================================================= */

/**
 * @brief  从 /proc/meminfo 读取 MemAvailable(KB)
 * @return 可用内存(KB),读取失败返回 -1
 */
int get_free_memory_kb(void) {
    FILE *fp = fopen("/proc/meminfo", "r");
    if (!fp) return -1;

    char line[128];
    int available_kb = -1;
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "MemAvailable:", 13) == 0) {
            sscanf(line + 13, "%d", &available_kb);
            break;
        }
    }
    fclose(fp);

    /* 部分旧内核无 MemAvailable,回退到 MemFree */
    if (available_kb < 0) {
        fp = fopen("/proc/meminfo", "r");
        if (fp) {
            while (fgets(line, sizeof(line), fp)) {
                if (strncmp(line, "MemFree:", 8) == 0) {
                    sscanf(line + 8, "%d", &available_kb);
                    break;
                }
            }
            fclose(fp);
        }
    }
    return available_kb;
}

/**
 * @brief  检查系统内存是否满足操作最低要求
 * @param  min_kb  最小可用内存阈值(KB)
 * @return true=内存充足,false=内存不足(应跳过操作)
 */
bool check_system_memory_ok(int min_kb) {
    int free_kb = get_free_memory_kb();
    if (free_kb < 0) {
        LOGW("check_system_memory_ok: failed to read meminfo, assuming OK");
        return true;
    }
    if (free_kb < min_kb) {
        LOGW("check_system_memory_ok: low memory %dKB < %dKB threshold, skip",
             free_kb, min_kb);
        return false;
    }
    return true;
}

/* =========================================================
 * Section 3: RTL8189FTV 驱动管理
 * ========================================================= */

/**
 * @brief  检测 RTL8189FTV 驱动是否已加载
 * @return true=已加载
 */
bool rtl8189ftv_is_driver_loaded(void) {
    /* 通过 /proc/modules 判断 */
    FILE *fp = fopen("/proc/modules", "r");
    if (!fp) return false;
    char line[256];
    bool found = false;
    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, RTL8189FTV_MODULE_NAME)) {
            found = true;
            break;
        }
    }
    fclose(fp);
    return found;
}

/**
 * @brief  加载 RTL8189FTV 驱动(insmod)
 * @return 0=成功,-1=失败
 */
int rtl8189ftv_load_driver(void) {
    if (rtl8189ftv_is_driver_loaded()) {
        LOGI("rtl8189ftv driver already loaded");
        return 0;
    }

    /* 检查 .ko 文件是否存在 */
    if (access(RTL8189FTV_KO_PATH, F_OK) != 0) {
        LOGE("rtl8189ftv: ko not found at %s", RTL8189FTV_KO_PATH);
        return -1;
    }

    char *argv[] = { (char*)"/sbin/insmod", (char*)RTL8189FTV_KO_PATH, NULL };
    int ret = run_cmd_timeout("/sbin/insmod", argv, 10);
    if (ret != 0) {
        LOGE("rtl8189ftv: insmod failed (ret=%d)", ret);
        return -1;
    }

    /* 等待接口出现,最多 5 秒 */
    for (int i = 0; i < 50; i++) {
        if (iface_exists(HW_NAME)) {
            LOGI("rtl8189ftv: driver loaded, iface %s ready", HW_NAME);
            return 0;
        }
        usleep(100000); /* 100ms */
    }
    LOGE("rtl8189ftv: driver loaded but iface %s not appeared", HW_NAME);
    return -1;
}

/**
 * @brief  卸载 RTL8189FTV 驱动(rmmod)
 * @return 0=成功,-1=失败
 */
int rtl8189ftv_unload_driver(void) {
    if (!rtl8189ftv_is_driver_loaded()) return 0;

    char *argv[] = { (char*)"/sbin/rmmod", (char*)RTL8189FTV_MODULE_NAME, NULL };
    int ret = run_cmd_timeout("/sbin/rmmod", argv, 10);
    if (ret != 0) {
        LOGE("rtl8189ftv: rmmod failed (ret=%d)", ret);
        return -1;
    }
    usleep(500000); /* 等待 500ms 让内核释放资源 */
    LOGI("rtl8189ftv: driver unloaded");
    return 0;
}

/**
 * @brief  重载驱动(unload + load)
 * @return 0=成功,-1=失败
 */
int rtl8189ftv_reload_driver(void) {
    LOGI("rtl8189ftv: reloading driver...");
    rtl8189ftv_unload_driver();
    sleep(1);
    return rtl8189ftv_load_driver();
}

/* =========================================================
 * Section 4: 网络接口操作(ioctl)
 * ========================================================= */

/**
 * @brief  创建 ioctl 用的临时 socket(使用后必须 close)
 */
static int _open_ioctl_sock(void) {
    return socket(AF_INET, SOCK_DGRAM, 0);
}

/**
 * @brief  检测网络接口是否存在
 */
bool iface_exists(const char *ifname) {
    int fd = _open_ioctl_sock();
    if (fd < 0) return false;
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    bool exists = (ioctl(fd, SIOCGIFINDEX, &ifr) == 0);
    close(fd);
    return exists;
}

/**
 * @brief  启动网络接口(IFF_UP)
 */
int iface_up(const char *ifname) {
    int fd = _open_ioctl_sock();
    if (fd < 0) return -1;
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { close(fd); return -1; }
    ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
    int ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
    close(fd);
    if (ret < 0) LOGE("iface_up(%s) failed: %s", ifname, strerror(errno));
    return ret;
}

/**
 * @brief  关闭网络接口(清除 IFF_UP)
 */
int iface_down(const char *ifname) {
    int fd = _open_ioctl_sock();
    if (fd < 0) return -1;
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { close(fd); return -1; }
    ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
    int ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
    close(fd);
    return ret;
}

/* =========================================================
 * Section 5: Wi-Fi 状态检测(WEXT ioctl)
 * ========================================================= */

/**
 * @brief  通过 ioctl(SIOCGIWSTATS) 获取信号强度(dBm)
 *         RTL8189FTV 驱动完整支持 WEXT,此方法可靠
 * @param  rssi_dbm  输出参数,信号强度(负数 dBm)
 * @return 0=成功,-1=失败(接口不存在或未关联)
 */
int wifi_get_rssi(int *rssi_dbm) {
    int fd = _open_ioctl_sock();
    if (fd < 0) return -1;

    struct iwreq iwr;
    struct iw_statistics stats;
    memset(&iwr, 0, sizeof(iwr));
    memset(&stats, 0, sizeof(stats));

    strncpy(iwr.ifr_name, HW_NAME, IFNAMSIZ - 1);
    iwr.u.data.pointer = &stats;
    iwr.u.data.length  = sizeof(stats);
    iwr.u.data.flags   = 1; /* 清除统计标志 */

    if (ioctl(fd, SIOCGIWSTATS, &iwr) < 0) {
        close(fd);
        return -1;
    }
    close(fd);

    /*
     * RTL8189FTV 驱动报告的 qual.level 为无符号 dBm+256 偏移
     * 转换规则:level >= 64 时,rssi = level - 256
     *           level <  64 时,rssi = level (罕见)
     */
    uint8_t raw_level = (uint8_t)stats.qual.level;
    *rssi_dbm = (raw_level >= 64) ? (int)raw_level - 256 : (int)raw_level;
    return 0;
}

/**
 * @brief  通过 ioctl(SIOCGIFADDR) 获取当前 IP 地址
 */
bool wifi_get_ip(char *ip_buf, int buf_len) {
    int fd = _open_ioctl_sock();
    if (fd < 0) return false;

    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, HW_NAME, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
        close(fd);
        return false;
    }
    close(fd);

    struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
    const char *ip_str = inet_ntoa(addr->sin_addr);
    if (!ip_str || strcmp(ip_str, "0.0.0.0") == 0) return false;
    strncpy(ip_buf, ip_str, buf_len - 1);
    ip_buf[buf_len - 1] = '\0';
    return true;
}

/**
 * @brief  从 /proc/net/route 获取默认网关 IP
 */
bool wifi_get_gateway(char *gw_buf, int buf_len) {
    FILE *fp = fopen("/proc/net/route", "r");
    if (!fp) return false;

    char line[256], iface[16];
    uint32_t dest, gw, mask;
    bool found = false;

    fgets(line, sizeof(line), fp); /* 跳过表头 */
    while (fgets(line, sizeof(line), fp)) {
        if (sscanf(line, "%15s %x %x %*s %*s %*s %*s %x",
                   iface, &dest, &gw, &mask) == 4) {
            if (dest == 0 && strcmp(iface, HW_NAME) == 0) {
                struct in_addr addr;
                addr.s_addr = gw;
                strncpy(gw_buf, inet_ntoa(addr), buf_len - 1);
                gw_buf[buf_len - 1] = '\0';
                found = true;
                break;
            }
        }
    }
    fclose(fp);
    return found;
}

/**
 * @brief  检查 wpa_supplicant 是否已完成认证(COMPLETED 状态)
 *         通过读取 /proc/net/wireless 判断是否有活跃连接
 *         (更可靠的方式是 wpa_cli status,此处用轻量 proc 方式)
 */
bool wifi_is_wpa_completed(void) {
    /* 方法:检查 /proc/net/wireless 中 wlan0 的 link quality > 0 */
    FILE *fp = fopen("/proc/net/wireless", "r");
    if (!fp) return false;

    char line[256];
    fgets(line, sizeof(line), fp); /* 跳过 2 行表头 */
    fgets(line, sizeof(line), fp);

    bool connected = false;
    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, HW_NAME)) {
            /* 格式:iface: status link level noise ... */
            int status = 0, link = 0;
            char iface[16];
            sscanf(line, "%15[^:]: %d %d", iface, &status, &link);
            connected = (link > 0);
            break;
        }
    }
    fclose(fp);
    return connected;
}

/* =========================================================
 * Section 6: 网络连通性检测(Raw Socket ICMP)
 * ========================================================= */

/**
 * @brief  ICMP 校验和计算
 */
static uint16_t _icmp_checksum(const void *data, size_t len) {
    const uint16_t *p = (const uint16_t *)data;
    uint32_t sum = 0;
    while (len > 1) { sum += *p++; len -= 2; }
    if (len) sum += *(const uint8_t *)p;
    while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
    return (uint16_t)~sum;
}

/**
 * @brief  快速 ICMP Ping(Raw Socket,不调用系统 ping 命令)
 * @param  ip_str   目标 IP(字符串)
 * @param  timeout_ms  超时时间(毫秒)
 * @return true=可达,false=不可达
 */
static bool _quick_ping(const char *ip_str, int timeout_ms) {
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sock < 0) {
        /* Raw socket 需要 root 权限;无权限时回退到 TCP 探测 */
        goto fallback_tcp;
    }

    /* 设置接收超时 */
    struct timeval tv = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

    struct sockaddr_in dest;
    memset(&dest, 0, sizeof(dest));
    dest.sin_family = AF_INET;
    inet_aton(ip_str, &dest.sin_addr);

    /* 构造 ICMP Echo Request */
    struct {
        struct icmphdr hdr;
        char payload[16];
    } pkt;
    memset(&pkt, 0, sizeof(pkt));
    pkt.hdr.type             = ICMP_ECHO;
    pkt.hdr.code             = 0;
    pkt.hdr.un.echo.id       = (uint16_t)getpid();
    pkt.hdr.un.echo.sequence = 1;
    memcpy(pkt.payload, "wifi_probe_ping", 15);
    pkt.hdr.checksum = _icmp_checksum(&pkt, sizeof(pkt));

    if (sendto(sock, &pkt, sizeof(pkt), 0,
               (struct sockaddr *)&dest, sizeof(dest)) <= 0) {
        close(sock);
        goto fallback_tcp;
    }

    char recv_buf[128];
    struct sockaddr_in from;
    socklen_t from_len = sizeof(from);
    ssize_t n = recvfrom(sock, recv_buf, sizeof(recv_buf), 0,
                          (struct sockaddr *)&from, &from_len);
    close(sock);
    return (n > 0);

fallback_tcp:
    /* Fallback:TCP 连接目标 53 端口(DNS),探测连通性 */
    {
        int tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
        if (tcp_sock < 0) return false;

        struct timeval tv2 = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
        setsockopt(tcp_sock, SOL_SOCKET, SO_SNDTIMEO, &tv2, sizeof(tv2));
        setsockopt(tcp_sock, SOL_SOCKET, SO_RCVTIMEO, &tv2, sizeof(tv2));

        /* 设置非阻塞以便超时控制 */
        int flags = fcntl(tcp_sock, F_GETFL, 0);
        fcntl(tcp_sock, F_SETFL, flags | O_NONBLOCK);

        struct sockaddr_in sa;
        memset(&sa, 0, sizeof(sa));
        sa.sin_family = AF_INET;
        sa.sin_port   = htons(PING_TARGET_PORT);
        inet_aton(ip_str, &sa.sin_addr);

        connect(tcp_sock, (struct sockaddr *)&sa, sizeof(sa));

        fd_set wset;
        FD_ZERO(&wset);
        FD_SET(tcp_sock, &wset);
        struct timeval tv3 = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
        bool reachable = (select(tcp_sock + 1, NULL, &wset, NULL, &tv3) > 0);
        close(tcp_sock);
        return reachable;
    }
}

/**
 * @brief  检测默认网关是否可达
 */
bool check_gateway_reachable(const char *gw_ip) {
    if (!gw_ip || gw_ip[0] == '\0') return false;
    return _quick_ping(gw_ip, PING_TIMEOUT_MS);
}

/**
 * @brief  检测公网连通性(8.8.8.8:53)
 */
bool check_internet_reachable(void) {
    return _quick_ping(PING_TARGET_PUBLIC, PING_TIMEOUT_MS);
}

/* =========================================================
 * Section 7: wpa_supplicant 管理
 * ========================================================= */

/**
 * @brief  写入 wpa_supplicant.conf 配置文件
 *         支持 WPA/WPA2/WPA3 和开放网络
 */
int wpa_write_config(const wifi_config_t *cfg) {
    FILE *fp = fopen(WPA_CONF_PATH, "w");
    if (!fp) {
        LOGE("wpa_write_config: cannot open %s", WPA_CONF_PATH);
        return -1;
    }

    fprintf(fp, "ctrl_interface=%s\n", WPA_CTRL_PATH);
    fprintf(fp, "ctrl_interface_group=0\n");
    fprintf(fp, "update_config=1\n\n");
    fprintf(fp, "network={\n");
    fprintf(fp, "    ssid=\"%s\"\n", cfg->ssid);

    if (cfg->bssid[0] != '\0') {
        fprintf(fp, "    bssid=%s\n", cfg->bssid);
    }

    if (cfg->password[0] == '\0') {
        /* 开放网络 */
        fprintf(fp, "    key_mgmt=NONE\n");
    } else {
        fprintf(fp, "    psk=\"%s\"\n", cfg->password);
        switch (cfg->proto) {
        case 1:
            fprintf(fp, "    proto=WPA\n");
            fprintf(fp, "    key_mgmt=WPA-PSK\n");
            fprintf(fp, "    pairwise=CCMP TKIP\n");
            fprintf(fp, "    group=CCMP TKIP\n");
            break;
        case 3: /* WPA3-SAE */
            fprintf(fp, "    proto=RSN\n");
            fprintf(fp, "    key_mgmt=SAE\n");
            fprintf(fp, "    pairwise=CCMP\n");
            fprintf(fp, "    group=CCMP\n");
            break;
        case 2:
        default: /* WPA2(推荐 RTL8189FTV 默认使用) */
            fprintf(fp, "    proto=RSN\n");
            fprintf(fp, "    key_mgmt=WPA-PSK\n");
            fprintf(fp, "    pairwise=CCMP\n");
            fprintf(fp, "    group=CCMP TKIP\n");
            break;
        }
    }

    fprintf(fp, "    scan_ssid=1\n"); /* 支持隐藏 SSID */
    fprintf(fp, "}\n");
    fclose(fp);

    LOGI("wpa_write_config: ssid=[%s] proto=%d", cfg->ssid, cfg->proto);
    return 0;
}

/**
 * @brief  启动 wpa_supplicant(后台模式 -B)
 * @return 0=成功,-1=失败
 */
int wpa_start(void) {
    /* 确保控制目录存在 */
    mkdir(WPA_CTRL_PATH, 0700);

    char *argv[] = {
        (char*)WPA_SUPPLICANT_BIN,
        (char*)"-B",              /* 后台运行 */
        (char*)"-D", (char*)"nl80211,wext",  /* RTL8189FTV 优先 nl80211 */
        (char*)"-i", (char*)HW_NAME,
        (char*)"-c", (char*)WPA_CONF_PATH,
        (char*)"-P", (char*)WPA_PID_FILE,
        NULL
    };

    int ret = run_cmd_timeout(WPA_SUPPLICANT_BIN, argv, 10);
    if (ret != 0) {
        LOGE("wpa_start: failed (ret=%d)", ret);
        return -1;
    }
    LOGI("wpa_start: wpa_supplicant launched");
    return 0;
}

/**
 * @brief  停止 wpa_supplicant
 */
void wpa_stop(void) {
    kill_process_by_pidfile(WPA_PID_FILE);
    kill_process_by_name("wpa_supplicant");
    unlink(WPA_CONF_PATH);
}

/**
 * @brief  等待 wpa_supplicant 完成认证(轮询 /proc/net/wireless)
 * @param  timeout_sec  超时秒数
 * @return 0=已连接,-1=超时
 */
int wpa_wait_connected(int timeout_sec) {
    time_t deadline = time(NULL) + timeout_sec;
    while (time(NULL) < deadline) {
        if (wifi_is_wpa_completed()) {
            LOGI("wpa_wait_connected: associated");
            return 0;
        }
        sleep(1);
    }
    LOGE("wpa_wait_connected: timeout after %ds", timeout_sec);
    return -1;
}

/* =========================================================
 * Section 8: DHCP 管理
 * ========================================================= */

/**
 * @brief  启动 udhcpc 获取 IP
 * @return 0=成功,-1=失败
 */
int dhcp_start(void) {
    char *argv[] = {
        (char*)UDHCPC_BIN,
        (char*)"-i", (char*)HW_NAME,
        (char*)"-p", (char*)UDHCPC_PID_FILE,
        (char*)"-t", (char*)"5",   /* 重试 5 次 */
        (char*)"-T", (char*)"3",   /* 每次 3 秒超时 */
        (char*)"-n",               /* 获取失败则退出(非守护模式) */
        NULL
    };

    int ret = run_cmd_timeout(UDHCPC_BIN, argv, DHCP_TIMEOUT_SEC);
    if (ret != 0) {
        LOGE("dhcp_start: udhcpc failed (ret=%d)", ret);
        return -1;
    }
    LOGI("dhcp_start: DHCP obtained");
    return 0;
}

/**
 * @brief  停止 udhcpc 并释放 IP
 */
void dhcp_stop(void) {
    kill_process_by_pidfile(UDHCPC_PID_FILE);
    kill_process_by_name("udhcpc");
}

/**
 * @brief  向 udhcpc 发送 SIGUSR1 触发 DHCP renew
 */
int dhcp_renew(void) {
    FILE *fp = fopen(UDHCPC_PID_FILE, "r");
    if (!fp) {
        /* PID 文件不存在,重新启动 DHCP */
        return dhcp_start();
    }
    int pid = 0;
    fscanf(fp, "%d", &pid);
    fclose(fp);
    if (pid > 1) {
        kill(pid, SIGUSR1);
        LOGI("dhcp_renew: sent SIGUSR1 to udhcpc pid=%d", pid);
        return 0;
    }
    return dhcp_start();
}

/* =========================================================
 * Section 9: 高层 Wi-Fi 连接接口
 * ========================================================= */

/**
 * @brief  完整的 Wi-Fi 连接流程
 *         步骤: 写配置 → 杀旧进程 → 加载驱动 → 接口 UP →
 *               启 wpa → 等待认证 → 启 DHCP → 检查 IP
 * @return 0=成功,-1=失败
 */
int wifi_connect(const wifi_config_t *cfg) {
    if (!cfg || cfg->ssid[0] == '\0') return -1;

    /* 内存检查 */
    if (!check_system_memory_ok(MIN_MEM_KB_FOR_OPERATION)) {
        LOGE("wifi_connect: insufficient memory, abort");
        return -1;
    }

    memcpy(&g_wifi_cfg, cfg, sizeof(g_wifi_cfg));

    pthread_mutex_lock(&g_stats_mutex);
    g_wifi_stats.state = WIFI_STATE_CONNECTING;
    pthread_mutex_unlock(&g_stats_mutex);

    LOGI("wifi_connect: connecting to [%s]", cfg->ssid);

    /* Step 1: 写 wpa_supplicant.conf */
    if (wpa_write_config(cfg) != 0) return -1;

    /* Step 2: 杀掉旧的 wpa_supplicant 和 udhcpc */
    dhcp_stop();
    wpa_stop();
    usleep(500000);

    /* Step 3: 确保驱动已加载(RTL8189FTV 特有) */
    if (rtl8189ftv_load_driver() != 0) {
        LOGE("wifi_connect: driver load failed");
        return -1;
    }

    /* Step 4: 接口 UP */
    if (iface_up(HW_NAME) != 0) {
        LOGE("wifi_connect: iface_up(%s) failed", HW_NAME);
        return -1;
    }
    usleep(300000);

    /* Step 5: 启动 wpa_supplicant */
    if (wpa_start() != 0) return -1;

    /* Step 6: 等待认证完成 */
    if (wpa_wait_connected(WIFI_CONNECT_TIMEOUT_SEC) != 0) {
        LOGE("wifi_connect: authentication timeout");
        pthread_mutex_lock(&g_stats_mutex);
        g_wifi_stats.state = WIFI_STATE_DISCONNECTED;
        pthread_mutex_unlock(&g_stats_mutex);
        return -1;
    }

    pthread_mutex_lock(&g_stats_mutex);
    g_wifi_stats.state = WIFI_STATE_AUTHENTICATED_NO_IP;
    pthread_mutex_unlock(&g_stats_mutex);

    /* Step 7: 启动 DHCP 获取 IP */
    if (dhcp_start() != 0) {
        LOGE("wifi_connect: DHCP failed");
        pthread_mutex_lock(&g_stats_mutex);
        g_wifi_stats.consecutive_dhcp_failures++;
        g_wifi_stats.state = WIFI_STATE_AUTHENTICATED_NO_IP;
        pthread_mutex_unlock(&g_stats_mutex);
        return -1;
    }

    /* Step 8: 验证 IP 已获取 */
    char ip[16] = {0};
    if (!wifi_get_ip(ip, sizeof(ip))) {
        LOGE("wifi_connect: got no IP after DHCP");
        return -1;
    }

    pthread_mutex_lock(&g_stats_mutex);
    strncpy(g_wifi_stats.ip, ip, sizeof(g_wifi_stats.ip) - 1);
    g_wifi_stats.state = WIFI_STATE_CONNECTED;
    g_wifi_stats.consecutive_dhcp_failures = 0;
    g_wifi_stats.total_reconnects++;
    pthread_mutex_unlock(&g_stats_mutex);

    LOGI("wifi_connect: connected! IP=%s", ip);
    return 0;
}

/**
 * @brief  断开 Wi-Fi 连接并清理资源
 */
void wifi_disconnect(void) {
    dhcp_stop();
    wpa_stop();
    iface_down(HW_NAME);

    pthread_mutex_lock(&g_stats_mutex);
    memset(g_wifi_stats.ip, 0, sizeof(g_wifi_stats.ip));
    g_wifi_stats.state = WIFI_STATE_DISCONNECTED;
    pthread_mutex_unlock(&g_stats_mutex);

    LOGI("wifi_disconnect: done");
}

wifi_state_t wifi_get_state(void) {
    pthread_mutex_lock(&g_stats_mutex);
    wifi_state_t s = g_wifi_stats.state;
    pthread_mutex_unlock(&g_stats_mutex);
    return s;
}

void wifi_get_stats(wifi_stats_t *stats) {
    pthread_mutex_lock(&g_stats_mutex);
    memcpy(stats, &g_wifi_stats, sizeof(wifi_stats_t));
    pthread_mutex_unlock(&g_stats_mutex);

    /* 实时更新信号强度 */
    wifi_get_rssi(&stats->rssi);
}

/* =========================================================
 * Section 10: 分级恢复
 * ========================================================= */

/**
 * @brief  P0 恢复:仅重启 DHCP(最轻量,不中断连接)
 */
void wifi_recovery_p0_dhcp(void) {
    if (!check_system_memory_ok(MIN_MEM_KB_FOR_OPERATION)) {
        LOGW("P0 recovery: skipped due to low memory");
        return;
    }
    LOGI("Wi-Fi recovery P0: restart DHCP");
    dhcp_stop();
    usleep(200000);
    int ret = dhcp_start();

    pthread_mutex_lock(&g_stats_mutex);
    if (ret == 0) {
        g_wifi_stats.consecutive_dhcp_failures = 0;
        char ip[16] = {0};
        wifi_get_ip(ip, sizeof(ip));
        strncpy(g_wifi_stats.ip, ip, sizeof(g_wifi_stats.ip) - 1);
    } else {
        g_wifi_stats.consecutive_dhcp_failures++;
    }
    pthread_mutex_unlock(&g_stats_mutex);
}

/**
 * @brief  P1 恢复:重启网络接口(iface down + up),不重载驱动
 */
void wifi_recovery_p1_interface(void) {
    if (!check_system_memory_ok(MIN_MEM_KB_FOR_OPERATION)) {
        LOGW("P1 recovery: skipped due to low memory");
        return;
    }
    LOGI("Wi-Fi recovery P1: restart interface %s", HW_NAME);
    dhcp_stop();
    wpa_stop();
    iface_down(HW_NAME);
    sleep(1);
    iface_up(HW_NAME);
    usleep(500000);
    wpa_start();
    wpa_wait_connected(WIFI_CONNECT_TIMEOUT_SEC);
    dhcp_start();
}

/**
 * @brief  P2 恢复:重载驱动模块 + 完整重连(最重量级)
 */
void wifi_recovery_p2_full_reset(void) {
    if (!check_system_memory_ok(MIN_MEM_KB_FOR_OPERATION)) {
        LOGW("P2 recovery: skipped due to low memory");
        return;
    }
    LOGI("Wi-Fi recovery P2: reload RTL8189FTV driver + full reconnect");

    dhcp_stop();
    wpa_stop();
    iface_down(HW_NAME);
    sleep(1);
    rtl8189ftv_reload_driver();
    sleep(1);
    wifi_connect(&g_wifi_cfg);

    pthread_mutex_lock(&g_stats_mutex);
    g_wifi_stats.consecutive_dhcp_failures = 0;
    g_wifi_stats.consecutive_gw_failures   = 0;
    pthread_mutex_unlock(&g_stats_mutex);
}

/* =========================================================
 * Section 11: NTP 时间同步(简化实现,用 ntpdate)
 * ========================================================= */

#define NTP_SYNC_INTERVAL_SEC   3600  /* 每小时同步一次 */
#define NTP_SERVER              "pool.ntp.org"

void wifi_ntp_sync_if_needed(void) {
    time_t now = time(NULL);
    if (now - g_last_ntp_sync < NTP_SYNC_INTERVAL_SEC) return;

    char *argv[] = { (char*)"/usr/sbin/ntpdate", (char*)"-u",
                     (char*)NTP_SERVER, NULL };
    int ret = run_cmd_timeout("/usr/sbin/ntpdate", argv, 10);
    if (ret == 0) {
        g_last_ntp_sync = now;
        LOGI("NTP sync OK");
    } else {
        LOGW("NTP sync failed (ret=%d)", ret);
    }
}

/* =========================================================
 * Section 12: Wi-Fi 守护线程(wifi_proc)
 * ========================================================= */

/**
 * @brief  Wi-Fi 状态机主循环(后台 pthread)
 *
 * 逻辑流程:
 *   1. 内存检查(极低内存则休眠等待)
 *   2. 检查 wpa 认证状态
 *   3. 检查 IP
 *   4. 检查网关连通性
 *   5. 检查公网连通性
 *   6. 按失败计数触发分级恢复
 *   7. NTP 同步
 */
void *wifi_proc(void *arg) {
    (void)arg;

    LOGI("wifi_proc: thread started");

    while (g_wifi_proc_running) {
        /* ---- 1. 临界内存检查 ---- */
        int mem_kb = get_free_memory_kb();
        if (mem_kb >= 0 && mem_kb < MIN_MEM_KB_CRITICAL) {
            LOGW("wifi_proc: critical low memory %dKB, sleeping 10s", mem_kb);
            sleep(10);
            continue;
        }

        /* ---- 2. WPA 认证状态检查 ---- */
        bool wpa_ok = wifi_is_wpa_completed();
        if (!wpa_ok) {
            LOGI("wifi_proc: WPA not connected, triggering reconnect");
            pthread_mutex_lock(&g_stats_mutex);
            g_wifi_stats.state = WIFI_STATE_DISCONNECTED;
            int dhcp_fails = g_wifi_stats.consecutive_dhcp_failures;
            pthread_mutex_unlock(&g_stats_mutex);

            if (dhcp_fails >= FULL_RESET_THRESHOLD) {
                wifi_recovery_p2_full_reset();
            } else {
                wifi_connect(&g_wifi_cfg);
            }
            sleep(WIFI_PROC_SLEEP_INTERVAL);
            continue;
        }

        /* ---- 3. IP 检查 ---- */
        char ip[16] = {0};
        if (!wifi_get_ip(ip, sizeof(ip))) {
            LOGI("wifi_proc: authenticated but no IP");
            pthread_mutex_lock(&g_stats_mutex);
            g_wifi_stats.state = WIFI_STATE_AUTHENTICATED_NO_IP;
            g_wifi_stats.consecutive_dhcp_failures++;
            int fails = g_wifi_stats.consecutive_dhcp_failures;
            pthread_mutex_unlock(&g_stats_mutex);

            if (fails >= FULL_RESET_THRESHOLD) {
                wifi_recovery_p2_full_reset();
            } else if (fails >= DHCP_RETRY_THRESHOLD) {
                wifi_recovery_p1_interface();
            } else {
                wifi_recovery_p0_dhcp();
            }
            sleep(WIFI_PROC_SLEEP_INTERVAL);
            continue;
        }

        /* 更新 IP */
        pthread_mutex_lock(&g_stats_mutex);
        strncpy(g_wifi_stats.ip, ip, sizeof(g_wifi_stats.ip) - 1);
        g_wifi_stats.consecutive_dhcp_failures = 0;
        pthread_mutex_unlock(&g_stats_mutex);

        /* ---- 4. 网关连通性检查 ---- */
        char gw[16] = {0};
        bool gw_ok = false;
        if (wifi_get_gateway(gw, sizeof(gw))) {
            gw_ok = check_gateway_reachable(gw);

            pthread_mutex_lock(&g_stats_mutex);
            strncpy(g_wifi_stats.gateway, gw, sizeof(g_wifi_stats.gateway) - 1);
            pthread_mutex_unlock(&g_stats_mutex);
        }

        if (!gw_ok) {
            pthread_mutex_lock(&g_stats_mutex);
            g_wifi_stats.consecutive_gw_failures++;
            int gw_fails = g_wifi_stats.consecutive_gw_failures;
            pthread_mutex_unlock(&g_stats_mutex);

            LOGW("wifi_proc: gateway unreachable (count=%d)", gw_fails);

            if (gw_fails >= GW_FAIL_THRESHOLD) {
                wifi_recovery_p1_interface();
            }
            sleep(WIFI_PROC_SLEEP_INTERVAL);
            continue;
        }

        /* 网关正常,重置计数 */
        pthread_mutex_lock(&g_stats_mutex);
        g_wifi_stats.consecutive_gw_failures = 0;
        pthread_mutex_unlock(&g_stats_mutex);

        /* ---- 5. 公网连通性检查 ---- */
        bool internet_ok = check_internet_reachable();
        pthread_mutex_lock(&g_stats_mutex);
        g_wifi_stats.state = internet_ok ? WIFI_STATE_CONNECTED
                                         : WIFI_STATE_NO_INTERNET;
        pthread_mutex_unlock(&g_stats_mutex);

        if (!internet_ok) {
            LOGW("wifi_proc: internet unreachable (LAN only)");
        }

        /* ---- 6. 更新信号强度 ---- */
        int rssi = 0;
        if (wifi_get_rssi(&rssi) == 0) {
            pthread_mutex_lock(&g_stats_mutex);
            g_wifi_stats.rssi = rssi;
            pthread_mutex_unlock(&g_stats_mutex);
        }

        /* ---- 7. NTP 校时 ---- */
        if (internet_ok) {
            wifi_ntp_sync_if_needed();
        }

        sleep(WIFI_PROC_SLEEP_INTERVAL);
    }

    LOGI("wifi_proc: thread exiting");
    return NULL;
}

/**
 * @brief  启动 Wi-Fi 守护线程
 * @param  cfg  Wi-Fi 连接配置
 * @return 0=成功,-1=失败
 */
int wifi_proc_start(const wifi_config_t *cfg) {
    if (cfg) memcpy(&g_wifi_cfg, cfg, sizeof(g_wifi_cfg));

    /* 先做一次初始连接 */
    if (wifi_connect(&g_wifi_cfg) != 0) {
        LOGW("wifi_proc_start: initial connect failed, will retry in thread");
    }

    g_wifi_proc_running = 1;
    int ret = pthread_create(&g_wifi_thread, NULL, wifi_proc, NULL);
    if (ret != 0) {
        LOGE("wifi_proc_start: pthread_create failed: %s", strerror(ret));
        g_wifi_proc_running = 0;
        return -1;
    }

    pthread_detach(g_wifi_thread);
    LOGI("wifi_proc_start: daemon thread started");
    return 0;
}

/**
 * @brief  停止 Wi-Fi 守护线程
 */
void wifi_proc_stop(void) {
    g_wifi_proc_running = 0;
    /* 等待线程自然退出(最多 2×INTERVAL) */
    sleep(WIFI_PROC_SLEEP_INTERVAL * 2 + 2);
    LOGI("wifi_proc_stop: done");
}

  代码基本上满足了当初的设计思路。这里未做测试。