鸿蒙适配wifi驱动(1)

本文首发于: LHM’s notes欢迎关注我的新博客

一入wifi深似海~

用户态(wpas)适配

首先找到如下目录,是开源wpas代码,由于之前看了点wpas的具体实现代码,知道在linux系统中wpas与内核打交道是通过两种标准接口,要么是nl80211接口,要么是wext(Wireless Extensions无线拓展接口); 由于当前内核系统更换,那么nl80211和wext自然是不适用了。因此猜想鸿蒙在wpas上有做适配,先到wpas源码上瞧了瞧,果然发现有新增文件。

/home/hmos/sourceCode/third_party/wpa_supplicant/wpa_supplicant-2.9/src/drivers
在这里插入图片描述

下面这个是鸿蒙框架下的wpa_driver_ops结构体,是继nl80211和wext之后的又一套新标准。由于上层只是调用指定的方法,如 get_ssid 、scan2等等,而对其具体实现不会关注,因此在整个鸿蒙适配wpas代码的过程中,只需要将这个g_wifiDriverOps对象的方法通过HDF框架实现即可,说实话,我对nl80211里面又臭又长的代码已经忍了很久了,希望这个不要让我失望:)

在这里插入图片描述

如上图所示,左边是wpas使用nl80211标准接口,右边是wpas使用鸿蒙wifi 接口;两者在上层业务面的改动基本不大,只是和内核交互的接口区域需要适配鸿蒙LiteOS。如下是接口部分的代码:
在这里插入图片描述

接下来我们以扫描业务为例子,分析鸿蒙wifi接口与内核态的交互过程。

扫描流程分析

首先看WifiWpaScan2内部实现

static int32_t WifiWpaScan2(void *priv, struct wpa_driver_scan_params *params)
{
    WifiScan *scan = NULL;
    WifiDriverData *drv = NULL;
    int32_t timeout;
    int32_t ret;

    if ((priv == NULL) || (params == NULL) || (params->num_ssids > WPAS_MAX_SCAN_SSIDS)) {
        return -EFAIL;
    }
    drv = (WifiDriverData *)priv;
    scan = (WifiScan *)os_zalloc(sizeof(WifiScan));
    if (scan == NULL) {
        return -EFAIL;
    }
    // 以下四个函数都是参数赋值,将param中的参数赋值到scan结构体中
    if ((WifiWpaScanProcessSsid(params, scan) != SUCC) || (WifiWpaScanProcessBssid(params, scan) != SUCC) ||
        (WifiWpaScanProcessExtraIes(params, scan) != SUCC) || (WifiWpaScanProcessFreq(params, scan) != SUCC)) {
        WifiWpaScanFree(&scan);
        return -EFAIL;
    }
	// scan结构体继续被填充
    scan->fastConnectFlag = WPA_FLAG_OFF;
    scan->prefixSsidScanFlag = WPA_FLAG_OFF;
    // 将填充好的scan 消息结构体发送给内核
    ret = WifiWpaCmdScan(drv->iface, scan);
    WifiWpaScanFree(&scan);

    timeout = SCAN_TIME_OUT;
    //在事件调度中注册超时处理机制
    eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx);
    eloop_register_timeout(timeout, 0, WifiWpaScanTimeout, drv, drv->ctx);

    return ret;
}

可以看到WifiWpaScan2只是一个结构体的填充并将该消息通过WifiWpaCmdScan去发送,具体发送流程进入看下:

int32_t WifiWpaCmdScan(const char *ifname, WifiScan *scan)
{
    int32_t ret;

    if (ifname == NULL || scan == NULL) {
        return -EFAIL;
    }

    struct HdfSBuf *data = HdfSBufObtainDefaultSize();
    if (data == NULL) {
        return -EFAIL;
    }
    bool isSerializeFailed = false;
    isSerializeFailed = isSerializeFailed || !HdfSbufWriteString(data, ifname);
    if (scan->bssid == NULL) {
        isSerializeFailed = isSerializeFailed || !HdfSbufWriteBuffer(data, scan->bssid, 0);
    } else {
        isSerializeFailed = isSerializeFailed || !HdfSbufWriteBuffer(data, scan->bssid, ETH_ADDR_LEN);
    }
    isSerializeFailed =
        isSerializeFailed || !HdfSbufWriteBuffer(data, scan->ssids, sizeof(scan->ssids[0]) * scan->numSsids);
    isSerializeFailed = isSerializeFailed || !HdfSbufWriteBuffer(data, scan->extraIes, scan->extraIesLen);
    isSerializeFailed =
        isSerializeFailed || !HdfSbufWriteBuffer(data, scan->freqs, sizeof(scan->freqs[0]) * scan->numFreqs);
    isSerializeFailed = isSerializeFailed || !HdfSbufWriteUint8(data, scan->prefixSsidScanFlag);
    isSerializeFailed = isSerializeFailed || !HdfSbufWriteUint8(data, scan->fastConnectFlag);
    if (isSerializeFailed) {
        wpa_printf(MSG_ERROR, "Serialize failed!");
        ret = -EFAIL;
    } else {
        ret = WifiWpaCmdBlockSyncSend(WIFI_WPA_CMD_SCAN, data, NULL);
    }
    HdfSBufRecycle(data);
    return ret;
}

看过鸿蒙驱动开发实战那章的对这个代码一定不会陌生,由于鸿蒙dispatch服务的参数类型是固定的,是struct HdfSBuf *类型,因此这里将发送数据通过HdfSbufWriteBuffer重新又拷贝到了struct HdfSBuf *指针里面, 并通过WifiWpaCmdBlockSyncSend进行发送,打开进入

int32_t WifiWpaCmdBlockSyncSend(const uint32_t cmd, struct HdfSBuf *reqData, struct HdfSBuf *respData)
{
    if (reqData == NULL) {
        HDF_LOGE("%s params is NULL", __func__);
        return HDF_FAILURE;
    }
    if (g_wifiService == NULL || g_wifiService->dispatcher == NULL || g_wifiService->dispatcher->Dispatch == NULL) {
        HDF_LOGE("%s:bad remote service found!", __func__);
        return HDF_FAILURE;
    }
    int32_t ret = g_wifiService->dispatcher->Dispatch(&g_wifiService->object, cmd, reqData, respData);
    HDF_LOGI("%s: cmd=%d, ret=%d", __func__, cmd, ret);
    return ret;
}

可以看到通信手法正是上面两章讲到的HDF service机制。

总结:

除了扫描流程、还有认证流程、关联流程,这些都是接下来去看的内容。目前对内核通信的机制基本有了了解,下面需要关注的有两点。

1、业务:消息中填充的每个数据,代表了什么含义;各个业务之间又是如何关联起来的。

2、驱动实现:消息发送到了内核,内核如何去处理,这驱动具体实现又和wifi芯片相关,也需要去了解。

猜你喜欢

转载自blog.csdn.net/u012323667/article/details/111570543
今日推荐