4. 解析 WiFi HAL 的 HIDL 接口定义

任务说明

本案例实现Android WiFi HAL层中设置WiFi接口模式的核心逻辑。目标是通过HAL接口将指定无线网卡(如wlan0)设置为STA(Station)或AP(Access Point)模式,并完成模式切换时的底层驱动调用。案例聚焦于HAL层函数set_interface_mode的完整实现,包括模式合法性校验、驱动命令下发以及结果返回。

核心实现

// wifi_hal_mode_control.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/wireless.h>
#include <errno.h>

#define WIFI_INTERFACE_NAME_MAX 16
#define WIFI_DRIVER_CMD_BUF_SIZE 64

typedef enum {
    WIFI_MODE_STA = 0,
    WIFI_MODE_AP  = 1,
    WIFI_MODE_INVALID
} wifi_mode_t;

typedef struct {
    char ifname[WIFI_INTERFACE_NAME_MAX];
    wifi_mode_t mode;
} wifi_interface_mode_t;

// 向驱动下发模式设置命令
static int wifi_driver_set_mode(const char *ifname, wifi_mode_t mode) {
    int sock = -1;
    struct iwreq wrq;
    char cmd_buf[WIFI_DRIVER_CMD_BUF_SIZE];

    if (ifname == NULL || strlen(ifname) == 0) {
        return -EINVAL;
    }

    // 创建socket用于ioctl
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        return -errno;
    }

    memset(&wrq, 0, sizeof(wrq));
    memset(cmd_buf, 0, sizeof(cmd_buf));

    // 构造驱动私有命令: SET_MODE=0 表示STA, SET_MODE=1 表示AP
    snprintf(cmd_buf, sizeof(cmd_buf), "SET_MODE=%d", (mode == WIFI_MODE_AP) ? 1 : 0);
    strncpy(wrq.ifr_name, ifname, IFNAMSIZ - 1);
    wrq.u.data.pointer = cmd_buf;
    wrq.u.data.length = strlen(cmd_buf) + 1;
    wrq.u.data.flags = 0;

    // 通过SIOCSIWPRIV下发驱动命令
    if (ioctl(sock, SIOCSIWPRIV, &wrq) < 0) {
        close(sock);
        return -errno;
    }

    close(sock);
    return 0;
}

// HAL层对外接口:设置WiFi接口模式
int set_interface_mode(const wifi_interface_mode_t *config) {
    if (config == NULL) {
        return -EINVAL;
    }

    // 校验接口名合法性
    if (strlen(config->ifname) == 0 ||
        strlen(config->ifname) >= WIFI_INTERFACE_NAME_MAX) {
        return -EINVAL;
    }

    // 校验模式合法性
    if (config->mode != WIFI_MODE_STA && config->mode != WIFI_MODE_AP) {
        return -EINVAL;
    }

    // 调用驱动下发模式设置命令
    int ret = wifi_driver_set_mode(config->ifname, config->mode);
    if (ret != 0) {
        return ret;
    }

    return 0;
}

关键逻辑说明

上述代码实现了完整的模式设置链路:set_interface_mode作为HAL层对外接口,首先校验传入的接口名和模式参数,随后通过wifi_driver_set_mode函数构造驱动私有命令SET_MODE=0/1,并利用SIOCSIWPRIVioctl调用下发至内核无线驱动。驱动收到命令后完成硬件模式切换。返回值0表示成功,负值对应标准errno错误码。

SVG:模式设置调用流程

Framework set_interface_mode() HAL层 参数校验 构造命令 SET_MODE=0/1 ioctl SIOCSIWPRIV 内核WiFi驱动 硬件模式切换 错误处理 返回负值errno 成功返回0 失败返回负值 参数非法 异常路径 正常路径

编译与使用

# 编译(需Linux内核头文件)
gcc -c wifi_hal_mode_control.c -o wifi_hal_mode_control.o

# 链接生成可执行测试程序(示例main函数需自行添加)
# gcc wifi_hal_mode_control.o -o wifi_mode_test

验证方法

编写测试程序调用set_interface_mode,传入合法的接口名(如"wlan0")和模式值,观察返回值:

  • 返回0:驱动命令下发成功,接口模式已切换;
  • 返回-EINVAL:参数非法(接口名为空或模式值不在枚举范围内);
  • 返回其他负值:驱动命令执行失败,可通过errno或返回值值判断具体错误原因。

在真实硬件环境中,可通过iwconfig命令确认接口模式已从"Managed"(STA)切换为"Master"(AP),或反之。若驱动不支持SET_MODE私有命令,ioctl将返回-EOPNOTSUPP,此时需确认驱动已实现对应命令处理。