WLAN

Overview

The WLAN module is developed based on the Hardware Driver Foundation (HDF). It supports cross-OS migration, component adaptation, and modular assembly and compilation. Based on the unified APIs provided by the WLAN module, driver developers of WLAN vendors can adapt their driver code and are capable of creating, disabling, scanning, and connecting to WLAN hotspots. The WLAN driver provides the Hardware Driver Interface (HDI) layer with the capabilities of setting and obtaining the device MAC address and setting the transmit power. The following figure shows the framework of the WLAN module:

Figure 1 WLAN framework

WLAN Driver API Architecture

The WLAN module provides the following three types of APIs:

  1. Capability APIs for the HDI layer

  2. Capability APIs directly invoked by drivers

  3. Capability APIs for vendors

Figure 2 Available APIs of the WLAN module

Available APIs

The WLAN driver module provides APIs that can be directly called by driver developers, such as creating/releasing a WifiModule, connecting to/disconnecting from a WLAN hotspot, applying for/releasing a NetBuf, and converting between the pbuf structure of Lightweight IP (lwIP) and a NetBuf. Table 1 describes some APIs.

Table 1 APIs that can be directly called by driver developers

File

Function

Description

wifi_module.h

struct WifiModule *WifiModuleCreate(const struct HdfConfigWifiModuleConfig *config);

Creates a WifiModule.

void WifiModuleDelete(struct WifiModule *module);

Deletes a WifiModule and releases its data.

int32_t DelFeature(struct WifiModule *module, uint16_t featureType);

Deletes a feature from a WifiModule.

int32_t AddFeature(struct WifiModule *module, uint16_t featureType, struct WifiFeature *featureData);

Adds a feature to a WifiModule.

wifi_mac80211_ops.h

int32_t (*startAp)(NetDevice *netDev);

Starts an AP.

int32_t (*stopAp)(NetDevice *netDev);

Stops an AP.

int32_t (*connect)(NetDevice *netDev, WifiConnectParams *param);

Connects to a hotspot.

int32_t (*disconnect)(NetDevice *netDev, uint16_t reasonCode);

Disconnects from a hotspot.

hdf_netbuf.h

static inline void NetBufQueueInit(struct NetBufQueue *q);

Initializes a NetBuf queue.

struct NetBuf *NetBufAlloc(uint32_t size);

Applies for a NetBuf.

void NetBufFree(struct NetBuf *nb);

Releases a NetBuf.

struct NetBuf *Pbuf2NetBuf(const struct NetDevice *netdev, struct pbuf *lwipBuf);

Converts the pbuf structure of lwIP to a NetBuf.

struct pbuf *NetBuf2Pbuf(const struct NetBuf *nb);

Converts a NetBuf to the pbuf structure of lwIP.

The WLAN driver module provides APIs for driver developers, such as initializing/deregistering, opening/stopping a NetDevice, and obtaining the state of a NetDevice. Table 2 describes some APIs.

Table 2 APIs for driver developers of WLAN vendors to implement

File

Function

Description

net_device.h

int32_t (*init)(struct NetDevice *netDev);

Initializes a NetDevice.

struct NetDevStats *(*getStats)(struct NetDevice *netDev);

Obtains the state of a NetDevice.

int32_t (*setMacAddr)(struct NetDevice *netDev, void *addr);

Sets the MAC address.

void (*deInit)(struct NetDevice *netDev);

Deinitializes a NetDevice.

int32_t (*open)(struct NetDevice *netDev);

Opens a NetDevice.

int32_t (*stop)(struct NetDevice *netDev);

Stops a NetDevice.

The WLAN driver provides the HDI layer with the APIs for creating and destroying an IWiFi object and setting the MAC address. Table 3 describes some APIs.

Table 3 APIs provided by the WLAN HAL module

Header File

Function

Description

wifi_hal.h

int32_t WifiConstruct(struct IWiFi **wifiInstance);

Creates an IWiFi object with basic capabilities.

int32_t WifiDestruct(struct IWiFi **wifiInstance);

Destroys an IWiFi object.

int32_t (*start)(struct IWiFi *);

Creates a channel between the HAL and the driver and obtains the NIC supported by the driver.

int32_t (*stop)(struct IWiFi *);

Stops the channel between the HAL and the driver.

wifi_hal_base_feature.h

int32_t (*getFeatureType)(const struct IWiFiBaseFeature *);

Obtains the feature type.

int32_t (*setMacAddress)(const struct IWiFiBaseFeature *, unsigned char *, uint8_t);

Sets the MAC address.

int32_t (*getDeviceMacAddress)(const struct IWiFiBaseFeature *, unsigned char *, uint8_t);

Obtains the device MAC address.

int32_t (*setTxPower)(const struct IWiFiBaseFeature *, int32_t);

Sets the transmit power.

Development Guidelines

The WLAN driver is developed based on the HDF and PLATFORM. It provides a unified driver model for WLAN modules of different vendors regardless of the operating system (OS) and system on a chip (SoC).

How to Develop

  1. Set hardware parameters such as module (different features) and chip in the wifi_config.hcs file.
  2. Parse the wifi_config.hcs file and generate a structure with the configured parameters.
  3. Initialize and create a module.
  4. Mount and initialize the chip.
  5. Initialize the bus.
  6. Mount the upper-layer WPA service.

NOTE: Some of the above adaptation steps have been provided. For details, see Development Example. The steps waiting to be performed by developers include setting configuration parameters based on hardware attributes, adapting and mounting a chip, and performing tests and verification.

Development Example

This example describes how to initialize a WLAN module. The following uses the Hi3881 WLAN chip as an example:

  1. Set parameters for the WLAN module based on hardware attributes.
/* Set parameters in the wlan_platform.hcs file based on hardware attributes. The following is an example of the WLAN platform configuration. */
hisi :& deviceList {
    device0 :: deviceInst {
        deviceInstId = 0;
        powers {
            power0 {
                powerSeqDelay = 0;  /* Power supply sequencing delay */
                powerType = 1;      /* Power supply type. Value 0 indicates that the power supply is always on, and value 1 indicates power supply through general-purpose input/output (GPIO). */
                gpioId = 1;         /* GPIO pin ID */
                activeLevel=1;      /* Active level. Value 0 indicates a low level, and value 1 indicates a high level. */
            }
            power1 {
                powerSeqDelay = 0;  /* Power supply sequencing delay */
                powerType = 0;      /* Power supply type. Value 0 indicates that the power supply is always on, and value 1 indicates power supply through GPIO. */
            }
        }
        reset {
            resetType = 0;         /* Reset type. Value 0 indicates that reset is not supported, and value 1 indicates reset through GPIO. */
            gpioId = 2;            /* GPIO pin ID */
            activeLevel=1;         /* Active level. Value 0 indicates a low level, and value 1 indicates a high level. */
            resetHoldTime = 30;    /* Hold time (ms) for a reset */
        }
        bootUpTimeout = 30;  /* Boot timeout duration (ms) */
        bus {
            busType = 0;     /* Bus type. Value 0 indicates secure digital input/output (SDIO). */
            busId = 2;      /* Bus ID */
            funcNum = [1];   /* SDIO function number */
            timeout = 1000;  /* Timeout duration for data read/write */
            blockSize = 512; /* Size of the data block to read or write */
        }
    }
}
/* Add the configuration file wlan_chip_<Chip name>.hcs (for example, wlan_chip_hi3881.hcs) for each chip and set parameters. The following uses the Hi3881 chip as an example. */
root {
    wlan_config {
        hi3881 :& chipList {
            chipHi3881 :: chipInst {
                match_attr = "hdf_wlan_chips_hi3881"; /* Match attribute */
                chipName = "hi3881";                   /* WLAN chip name */
                sdio {
                    vendorId = 0x0296;    /* Vendor ID */
                    deviceId = [0x5347];  /* Device ID */
                }
            }
        }
    }
}
  1. Mount the init and deinit functions of the WLAN chip and WLAN chip driver.
/* WLAN module initialization and mount process */
#include "hdf_device_desc.h"
#include "hdf_wifi_product.h"
#include "hdf_log.h"
#include "osal_mem.h"
#include "hdf_wlan_chipdriver_manager.h"
#include "securec.h"
#include "wifi_module.h"
#include "hi_wifi_api.h"
#include "hi_types_base.h"

#define HDF_LOG_TAG Hi3881Driver

/* Functions for initializing and deinitializing the WLAN chip */
int32_t InitHi3881Chip(struct HdfWlanDevice *device);
int32_t DeinitHi3881Chip(struct HdfWlanDevice *device);
/* Functions for initializing and deinitializing the WLAN chip driver */
int32_t Hi3881Deinit(struct HdfChipDriver* chipDriver, struct NetDevice *netDevice);
int32_t Hi3881Init(struct HdfChipDriver* chipDriver, struct NetDevice *netDevice);

/* Initialize mac80211 and mount functions of the chip. */
hi_void HiMac80211Init(struct HdfChipDriver *chipDriver);

static const char* const HI3881_DRIVER_NAME = "hisi";

/* Mount the WLAN chip driver and the functions of mac80211 and the chip. */
static struct HdfChipDriver *BuildHi3881Driver(struct HdfWlanDevice *device, uint8_t ifIndex)
{
    struct HdfChipDriver *specificDriver = NULL;
    if (device == NULL) {
        HDF_LOGE("%s fail : channel is NULL", __func__);
        return NULL;
    }
    (void)device;
    (void)ifIndex;
    specificDriver = (struct HdfChipDriver *)OsalMemCalloc(sizeof(struct HdfChipDriver));
    if (specificDriver == NULL) {
        HDF_LOGE("%s fail: OsalMemCalloc fail!", __func__);
        return NULL;
    }
    if (memset_s(specificDriver, sizeof(struct HdfChipDriver), 0, sizeof(struct HdfChipDriver)) != EOK) {
        HDF_LOGE("%s fail: memset_s fail!", __func__);
        OsalMemFree(specificDriver);
        return NULL;
    }

    if (strcpy_s(specificDriver->name, MAX_WIFI_COMPONENT_NAME_LEN, HI3881_DRIVER_NAME) != EOK) {
        HDF_LOGE("%s fail : strcpy_s fail", __func__);
        OsalMemFree(specificDriver);
        return NULL;
    }
    specificDriver->init = Hi3881Init;
    specificDriver->deinit = Hi3881Deinit;

    HiMac80211Init(specificDriver);

    return specificDriver;
}

/* Release the WLAN chip driver. */
static void ReleaseHi3881Driver(struct HdfChipDriver *chipDriver)
{
    if (chipDriver == NULL) {
        return;
    }
    if (strcmp(chipDriver->name, HI3881_DRIVER_NAME) != 0) {
        HDF_LOGE("%s:Not my driver!", __func__);
        return;
    }
    OsalMemFree(chipDriver);
}

static uint8_t GetHi3881GetMaxIFCount(struct HdfChipDriverFactory *factory) {
    (void)factory;
    return 1;
}

/* Register functions related to the WLAN chip. */
static int32_t HDFWlanRegHisiDriverFactory(void)
{
    static struct HdfChipDriverFactory tmpFactory = { 0 };
    struct HdfChipDriverManager *driverMgr = NULL;
    driverMgr = HdfWlanGetChipDriverMgr();
    if (driverMgr == NULL && driverMgr->RegChipDriver != NULL) {
        HDF_LOGE("%s fail: driverMgr is NULL!", __func__);
        return HDF_FAILURE;
    }
    tmpFactory.driverName = HI3881_DRIVER_NAME;
    tmpFactory.GetMaxIFCount = GetHi3881GetMaxIFCount;
    tmpFactory.InitChip = InitHi3881Chip;
    tmpFactory.DeinitChip = DeinitHi3881Chip;
    tmpFactory.Build = BuildHi3881Driver;
    tmpFactory.Release = ReleaseHi3881Driver;
    tmpFactory.ReleaseFactory = NULL;
    if (driverMgr->RegChipDriver(&tmpFactory) != HDF_SUCCESS) {
        HDF_LOGE("%s fail: driverMgr is NULL!", __func__);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t HdfWlanHisiChipDriverInit(struct HdfDeviceObject *device)
{
    (void)device;
    return HDFWlanRegHisiDriverFactory();
}

struct HdfDriverEntry g_hdfHisiChipEntry = {
    .moduleVersion = 1,
    .Init = HdfWlanHisiChipDriverInit,
    .moduleName = "HDF_WLAN_CHIPS"
};

HDF_INIT(g_hdfHisiChipEntry);
#include "hdf_wifi_product.h"
#include "hi_wifi_api.h"
#if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION)
#include "oal_thread.h"
#include "osal_time.h"
#endif
#include "wifi_mac80211_ops.h"
#include "wal_cfg80211.h"
#include "net_adpater.h"
#include "hdf_wlan_utils.h"

#define HDF_LOG_TAG Hi3881Driver

/* Initialize the WLAN chip. */
int32_t InitHi3881Chip(struct HdfWlanDevice *device)
{
    uint8_t maxPortCount = 1;
    int32_t ret = HI_SUCCESS;
    uint8_t maxRetryCount = 2;
    if (device == NULL) {
        HDF_LOGE("%s:NULL ptr!", __func__);
        return HI_FAIL;
    }

    do {
        if (ret != HI_SUCCESS) {
            if (device->reset != NULL && device->reset->Reset != NULL) {
                device->reset->Reset(device->reset);
            }
            HDF_LOGE("%s:Retry init hi3881!last ret=%d", __func__, ret);
        }
        ret = hi_wifi_init(maxPortCount);
    } while (ret != 0 && --maxRetryCount > 0);

    if (ret != 0) {
        HDF_LOGE("%s:Init hi3881 driver failed!", __func__);
        return ret;
    }
    return HI_SUCCESS;
}

/* Deinitialize the WLAN chip. */
int32_t DeinitHi3881Chip(struct HdfWlanDevice *device)
{
    (void)device;
    int32_t ret = hi_wifi_deinit();
    if (ret != 0) {
        HDF_LOGE("%s:Deinit failed!ret=%d", __func__, ret);
    }
    return ret;
}

/* Initialize the WLAN chip driver. */
int32_t Hi3881Init(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
{
    HDF_LOGI("%s: start...", __func__);
    hi_u16 mode = wal_get_vap_mode();
    int32_t ret;
    nl80211_iftype_uint8 type;
    (void)chipDriver;

    if (mode >= WAL_WIFI_MODE_BUTT) {
        oam_error_log1(0, 0, "wal_init_drv_netdev:: invalid mode[%d]", mode);
        return HI_FAIL;
    }

    if (mode == WAL_WIFI_MODE_STA) {
        type = NL80211_IFTYPE_STATION;
    } else if (mode == WAL_WIFI_MODE_AP) {
        type = NL80211_IFTYPE_AP;
    } else {
        oam_error_log1(0, 0, "wal_init_drv_netdev:: invalid mode[%d]", mode);
        return HI_FAIL;
    }

    ret = wal_init_drv_wlan_netdev(type, WAL_PHY_MODE_11N, netDevice);
    if (ret != HI_SUCCESS) {
        oam_error_log2(0, OAM_SF_ANY, "wal_init_drv_netdev %s failed.l_return:%d\n", netDevice->name, ret);
    }
    return ret;
}

/* Deinitialize the WLAN chip driver. */
int32_t Hi3881Deinit(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice)
{
    (void)chipDriver;
    int32_t ret = wal_deinit_drv_wlan_netdev(netDevice);
    if (ret != HDF_SUCCESS) {
        return ret;
    }
    return ReleasePlatformNetDevice(netDevice);
}
  1. During the chip initialization, call the NetDeviceInit() function to initialize a network device, call the NetDeviceAdd() function to add the network device to a protocol stack, and implement some function pointers of netdev.
hi_s32 wal_init_drv_wlan_netdev(nl80211_iftype_uint8 type, wal_phy_mode mode, hi_char* ifname, hi_u32* len)
{
    oal_net_device_stru *netdev          = HI_NULL;

    ......
    /* Initialize the network device and obtain the initialized instance. */
    netdev = NetDeviceInit(ifname, *len, LITE_OS);
    oal_wireless_dev *wdev = (oal_wireless_dev *)oal_mem_alloc(OAL_MEM_POOL_ID_LOCAL, sizeof(oal_wireless_dev));
    ret = wal_init_netif(type, netdev, wdev);

    ......

    return HI_SUCCESS;
}
/* Mount some function pointers of NetDeviceInterFace. */
oal_net_device_ops_stru g_wal_net_dev_ops =
{
    .getStats          = wal_netdev_get_stats,
    .open               = wal_netdev_open,
    .stop               = wal_netdev_stop,
    .xmit         = hmac_bridge_vap_xmit,
    .ioctl           = wal_net_device_ioctl,
    .changeMtu         = oal_net_device_change_mtu,
    .init              = oal_net_device_init,
    .deInit            = oal_net_free_netdev,
#if (defined(_PRE_WLAN_FEATURE_FLOWCTL) || defined(_PRE_WLAN_FEATURE_OFFLOAD_FLOWCTL))
    .selectQueue       = wal_netdev_select_queue,
#endif
    .setMacAddr    = wal_netdev_set_mac_addr,
#if (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
    .netifNotify       = HI_NULL,
#endif
    .specialEtherTypeProcess = SpecialEtherTypeProcess,
};

hi_s32 wal_init_netif(nl80211_iftype_uint8 type, oal_net_device_stru *netdev, const oal_wireless_dev *wdev)
{
    /* Add the network device to a protocol stack. */
    hi_u32 ret = NetDeviceAdd(netdev, (Protocol80211IfType)type);

    ......

    return HI_SUCCESS;
}
  1. Implement functions of WifiMac80211Ops.
/* Mount some function pointers of mac80211. */

/* MAC-layer APIs for basic capabilities that need to be implemented by the driver */
static struct HdfMac80211BaseOps g_baseOps = {
    .SetMode = WalSetMode,
    .AddKey = WalAddKey,
    .DelKey = WalDelKey,
    .SetDefaultKey = WalSetDefaultKey,
    .GetDeviceMacAddr = WalGetDeviceMacAddr,
    .SetMacAddr = WalSetMacAddr,
    .SetTxPower = WalSetTxPower,
    .GetValidFreqsWithBand = WalGetValidFreqsWithBand,
    .GetHwCapability = WalGetHwCapability
};

/* MAC-layer APIs for station capabilities that need to be implemented by the driver */
static struct HdfMac80211STAOps g_staOps = {
    .Connect = WalConnect,
    .Disconnect = WalDisconnect,
    .StartScan = WalStartScan,
    .AbortScan = WalAbortScan,
    .SetScanningMacAddress = WalSetScanningMacAddress,
};

/* MAC-layer APIs for AP capabilities that need to be implemented by the driver */
static struct HdfMac80211APOps g_apOps = {
    .ConfigAp = WalConfigAp,
    .StartAp = WalStartAp,
    .StopAp = WalStopAp,
    .ConfigBeacon = WalChangeBeacon,
    .DelStation = WalDelStation,
    .SetCountryCode = WalSetCountryCode,
    .GetAssociatedStasCount = WalGetAssociatedStasCount,
    .GetAssociatedStasInfo = WalGetAssociatedStasInfo
};

/* Initialize mac80211 and mount functions of the chip. */
hi_void HiMac80211Init(struct HdfChipDriver *chipDriver)
{
    if (chipDriver == NULL) {
        oam_error_log(0, OAM_SF_ANY, "%s:input is NULL!", __func__);
        return;
    }
    chipDriver->ops = &g_baseOps;
    chipDriver->staOps = &g_staOps;
    chipDriver->apOps = &g_apOps;
}