1# WLAN 2 3 4## 概述 5 6### 功能简介 7 8WLAN(Wireless Local Area Network)作为网络设备的一个重要特性,其驱动的开发也是设备开发过程中不可忽略的一部分。 9在OpenHarmony架构中,基于HDF(Hardware Driver Foundation)驱动框架开发的WLAN驱动模块,具备跨操作系统迁移、自适应器件差异、模块化拼装编译等特性。 10 11### 运作机制 12 13各WLAN设备厂商的驱动开发人员可根据WLAN模块提供的向下、向上的统一接口适配各自的驱动代码: 14 15- 向下统一接口实现的能力包括:建立/关闭WLAN热点、扫描、关联WLAN热点等。 16- 对HDI层向上提供能力包括:设置MAC地址、设置发射功率、获取设备的MAC地址等。 17 18WLAN框架如图1所示,其中WLAN Driver模块主要提供启动加载、配置文件解析、提供总线抽象接口等能力,WLAN Chip Driver模块主要提供MAC子层管理实体等。 19 20 **图1** WLAN框架 21 22 ![image](figures/WLAN框架.png "WLAN框架") 23 24 WLAN Driver框架如图2所示。 25 26 **图2** WLAN Driver框架 27 28 ![zh-cn_image_0000001300092359](figures/zh-cn_image_0000001300092359.png) 29 30WLAN Driver框架主要由如下模块组成: 31 321. WLAN Message:该部件为每个服务单独提供业务接口,每个服务也可依赖其他服务形成组合业务接口,此模块支持在用户态、内核态和MCU环境运行,实现部件间的充分解耦。 33 342. WLAN Configuration Core:WLAN相关的配置文件进行解析。 35 363. AP:AP(Access Point)为WLAN终端提供外部接入入口的设备。 37 384. STA:STA(Station)为接入WLAN系统的终端。 39 405. Mac80211:定义底层驱动相关的MAC层接口。 41 426. Bus:该驱动模块向上提供统一的总线抽象接口。通过向下调用Platform层提供的SDIO接口和封装适配USB、PCIE接口,屏蔽不同内核的差异;通过对不同类型的总线操作进行统一封装,屏蔽不同芯片差异,能够对不同芯片厂商提供完备的总线驱动能力,不同厂商共用此模块接口,从而使厂商的开发更为便捷和统一。 43 447. NetDevice:用于建立专属网络设备,屏蔽不同OS的差异,对WiFi驱动提供统一接口,提供统一的HDF NetDevice数据结构,及其统一管理、注册、去注册能力;对接轻设备及富设备上的Linux的网络设备层。 45 468. NetBuf:该部件为WLAN驱动提供Linux或者LiteOS原生的网络数据缓冲的统一数据结构的封装以及对网络数据的操作接口的封装。 47 489. FlowCtl:流控模块,当数据量过大时按照优先级策略处理数据。 49 5010. HCC-CFG:WLAN相关参数配置其中包括板级配置、驱动配置、Module配置。 51 52其中主要模块关系如下: 53 541. WLAN Driver通过HCC-CFG模块和WLAN Configuration Core模块进行配置文件的解析与加载。 55 562. WLAN Message将用户态的消息按组件分发至AP、STA等模块。 57 583. 对于命令字段则下发至Mac80211,再通过Bus模块发送到WLAN芯片固件侧。 59 604. 协议栈与NetDevice模块、NetBuf模块、FlowCtl模块共同协同完成数据流交互。 61 62## 开发指导 63 64### 接口说明 65 66WLAN模块有三部分对外开放的API接口,如下图所示: 67 681. 对上层服务提供HDI以及HAL能力接口。 69 702. 提供给各厂商实现的能力接口。 71 723. 驱动直接调用WLAN模块能力接口。 73 74 **图3** WLAN驱动接口框架图 75 76 ![image](figures/WLAN驱动接口框架图.png "WLAN驱动接口框架图") 77 78 79- WLAN驱动模块对上层服务提供的HAL能力接口(适用于小型系统及轻量系统),主要功能有:创建/销毁 IWiFi对象、设置MAC地址等。提供的部分接口说明如表2、表3所示: 80 81 **表1** wifi_hal.h 82 83 | 接口名称 | 功能描述 | 84 | -------- | -------- | 85 | int32_t WifiConstruct(struct IWiFi \*\*wifiInstance) | 创建IWiFi对象,提供IWiFi基本能力。 | 86 | int32_t WifiDestruct(struct IWiFi \*\*wifiInstance) | 销毁IWiFi对象。 | 87 | int32_t (\*start)(struct IWiFi \*) | 创建HAL和驱动之间的通道及获取驱动支持的网卡信息。 | 88 | int32_t (\*stop)(struct IWiFi \*) | 销毁通道。 | 89 90 **表2** wifi_hal_base_feature.h 91 92 | 接口名称 | 功能描述 | 93 | -------- | -------- | 94 | int32_t (\*getFeatureType)(const struct IWiFiBaseFeature \*) | 获取特性的类型。 | 95 | int32_t (\*setMacAddress)(const struct IWiFiBaseFeature \*, unsigned char \*, uint8_t) | 设置MAC地址。 | 96 | int32_t (\*getDeviceMacAddress)(const struct IWiFiBaseFeature \*, unsigned char \*, uint8_t) | 获取设备持久化的MAC地址。 | 97 | int32_t (\*setTxPower)(const struct IWiFiBaseFeature \*, int32_t) | 设置发射功率。 | 98 99- WLAN驱动模块也提供了需要驱动开发人员自行去填充具体实现内容的能力接口,主要功能有:初始化/注销NetDevice、打开/关闭NetDevice、获取NetDevice的状态等。提供的部分接口说明如表4所示: 100 101 **表3** net_device.h 102 103 | 接口名称 | 功能描述 | 104 | -------- | -------- | 105 | int32_t (\*init)(struct NetDevice \*netDev) | 初始化NetDevice。 | 106 | struct NetDevStats \*(\*getStats)(struct NetDevice \*netDev) | 获取NetDevice的状态。 | 107 | int32_t (\*setMacAddr)(struct NetDevice \*netDev, void \*addr) | 设置Mac地址。 | 108 | void (\*deInit)(struct NetDevice \*netDev) | 注销NetDevice。 | 109 | int32_t (\*open)(struct NetDevice \*netDev) | 打开NetDevice。 | 110 | int32_t (\*stop)(struct NetDevice \*netDev) | 关闭NetDevice。 | 111 112- WLAN驱动模块提供给驱动开发人员可直接调用的能力接口,主要功能有:创建/释放WifiModule、关联/取消关联、申请/释放NetBuf、lwip的pbuf和NetBuf的相互转换等。 113 114 可直接调用的接口如表5、表6和表7所示。 115 116 **表4** wifi_module.h 117 118 | 接口名称 | 功能描述 | 119 | -------- | -------- | 120 | struct WifiModule \*WifiModuleCreate(const struct HdfConfigWifiModuleConfig \*config) | 基于HDF开发WLAN驱动时,创建一个WifiModule。 | 121 | void WifiModuleDelete(struct WifiModule \*module) | 基于HDF开发WLAN驱动时,删除并释放WifiModule所有数据。 | 122 | int32_t DelFeature(struct WifiModule \*module, uint16_t featureType) | 基于HDF开发WLAN驱动时,从WifiModule删除一个功能组件。 | 123 | int32_t AddFeature(struct WifiModule \*module, uint16_t featureType,<br> struct WifiFeature \*featureData) | 基于HDF开发WLAN驱动时,注册一个功能组件到WifiModule。 | 124 125 **表5** wifi_mac80211_ops.h 126 127 | 接口名称 | 功能描述 | 128 | -------- | -------- | 129 | int32_t (\*startAp)(NetDevice \*netDev) | 启动AP。 | 130 | int32_t (\*stopAp)(NetDevice \*netDev) | 停止AP。 | 131 | int32_t (\*connect)(NetDevice \*netDev, WifiConnectParams \*param) | 开始关联。 | 132 | int32_t (\*disconnect)(NetDevice \*netDev, uint16_t reasonCode) | 取消关联。 | 133 134 **表6** hdf_netbuf.h 135 136 | 接口名称 | 功能描述 | 137 | -------- | -------- | 138 | static inline void NetBufQueueInit(struct NetBufQueue \*q) | 初始化NetBuf队列。 | 139 | struct NetBuf \*NetBufAlloc(uint32_t size) | 申请NetBuf。 | 140 | void NetBufFree(struct NetBuf \*nb) | 释放NetBuf。 | 141 | struct NetBuf \*Pbuf2NetBuf(const struct NetDevice \*netdev, struct pbuf \*lwipBuf) | lwip的pbuf转换为NetBuf。 | 142 | struct pbuf \*NetBuf2Pbuf(const struct NetBuf \*nb) | NetBuf转换为lwip的pbuf。 | 143 144### 开发步骤 145#### 厂商适配WLAN框架 146 147WLAN驱动基于HDF框架和Platform框架开发,不区分OS和芯片平台,为不同厂商的WLAN模组提供统一的驱动模型,各WLAN模组厂商根据如下开发流程适配WLAN驱动框架。 148 149**开发流程** 150 1511. 配置硬件(例如module、芯片等)相关的参数。wlan_platform.hcs文件中对参数进行配置后,HDF框架会对该文件进行解析,并生成全量配置的结构体对象。 152 1532. 初始化和去初始化WLAN模块相关适配(如WLAN芯片初始化和去初始化、WLAN芯片驱动初始化和去初始化)。 154 1553. 控制流命令下发的适配。 156 1574. 事件上报的调用。 158 159**开发实例** 160 161本例程提供WLAN模块初始化过程的完整使用流程。示例如下(以Hi3881WLAN芯片为例): 162 1631. Driver的HCS配置。 164 165 HCS文件配置包括:device相关配置和组件配置。 166 167 - device相关配置 168 169 配置文件内容包括:电源配置、复位配置和总线配置。 170 171 配置文件路径:vendor/<厂商名>/<设备名>/hdf_config/khdf/wifi。 172 173 根据硬件具体情况,在wlan_platform.hcs中配置相关参数,以下是WLAN平台配置的示例: 174 ```text 175 hisi :& deviceList { 176 device0 :: deviceInst { 177 deviceInstId = 0; 178 powers { 179 power0 { 180 powerSeqDelay = 0; /* 电源序列延时 */ 181 powerType = 1; /* 电源类型,0表示总是打开;1表示GPIO */ 182 gpioId = 1; /* GPIO管脚号 */ 183 activeLevel=1; /* 有效电平,0表示低电平有效;1表示高电平有效 */ 184 } 185 power1 { 186 powerSeqDelay = 0; /* 电源序列延时 */ 187 powerType = 0; /* 电源类型,0表示总是打开;1表示GPIO */ 188 } 189 } 190 reset { 191 resetType = 0; /* 复位类型,0表示不管理;1表示GPIO */ 192 gpioId = 2; /* GPIO管脚号 */ 193 activeLevel=1; /* 有效电平,0表示低电平有效;1表示高电平有效 */ 194 resetHoldTime = 30; /* 复位配置后的等待时间(ms) */ 195 } 196 bootUpTimeout = 30; /* 启动超时时间(ms) */ 197 bus { 198 busEnable = 1; /* bus总线是否初始化,0-表示不初始化; 1表示初始化 */ 199 busType = 0; /* 总线类型,0表示sdio */ 200 busId = 2; /* 总线号 */ 201 funcNum = [1]; /* SDIO功能号 */ 202 timeout = 1000; /* 读/写数据的超时时间 */ 203 blockSize = 512; /* 读/写数据的块大小 */ 204 } 205 } 206 } 207 ``` 208 - 组件配置 209 210 每一块芯片添加配置文件wlan_chip_<芯片名>.hcs(如:wlan_chip_hi3881.hcs),配置相关参数。以下是hi3881的配置示例: 211 ```text 212 root { 213 wlan_config { 214 hi3881 :& chipList { 215 chipHi3881 :: chipInst { 216 match_attr = "hdf_wlan_chips_hi3881"; /* 配置匹配标识 */ 217 chipName = "hi3881"; /* WLAN芯片的名称 */ 218 bus { 219 vendorId = 0x0296; /* 厂商ID */ 220 deviceId = [0x5347]; /* 设备ID */ 221 } 222 } 223 } 224 } 225 } 226 ``` 227 2282. 驱动适配挂接WLAN芯片的初始化和去初始化、WLAN芯片驱动的初始化和去初始化。 229 - 驱动适配入口函数实现 230 231 根据各自的芯片定义一个HdfDriverEntry类型的变量,主要实现Bind、Init、Release接口的函数挂接。调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源。 232 ```c 233 struct HdfDriverEntry g_hdfHisiChipEntry = { 234 .moduleVersion = 1, 235 .Bind = HdfWlanHisiDriverBind, 236 .Init = HdfWlanHisiChipDriverInit, 237 .Release = HdfWlanHisiChipRelease, 238 .moduleName = "HDF_WLAN_CHIPS" 239 }; 240 241 HDF_INIT(g_hdfHisiChipEntry); 242 ``` 243 244 - 芯片初始化,芯片驱动初始化函数的注册 245 246 InitChip/DeinitChip接口挂接芯片初始化、去初始化的函数实现。 247 248 Build/Release接口挂接芯片驱动的初始化、去初始化函数实现。 249 250 ```c 251 /* WLAN芯片相关函数的注册 */ 252 static int32_t HDFWlanRegHisiDriverFactory(void) 253 { 254 static struct HdfChipDriverFactory tmpFactory = { 0 }; 255 struct HdfChipDriverManager *driverMgr = NULL; 256 driverMgr = HdfWlanGetChipDriverMgr(); 257 if (driverMgr == NULL) { 258 HDF_LOGE("%s fail: driverMgr is NULL!", __func__); 259 return HDF_FAILURE; 260 } 261 tmpFactory.driverName = HI3881_DRIVER_NAME; 262 tmpFactory.GetMaxIFCount = GetHi3881GetMaxIFCount; 263 tmpFactory.InitChip = InitHi3881Chip; 264 tmpFactory.DeinitChip = DeinitHi3881Chip; 265 tmpFactory.Build = BuildHi3881Driver; 266 tmpFactory.Release = ReleaseHi3881Driver; 267 tmpFactory.ReleaseFactory = NULL; 268 if (driverMgr->RegChipDriver(&tmpFactory) != HDF_SUCCESS) { 269 HDF_LOGE("%s fail: driverMgr is NULL!", __func__); 270 return HDF_FAILURE; 271 } 272 273 return HDF_SUCCESS; 274 } 275 276 static int32_t HdfWlanHisiChipDriverInit(struct HdfDeviceObject *device) 277 { 278 (void)device; 279 return HDFWlanRegHisiDriverFactory(); 280 } 281 ``` 282 283 - 芯片的初始化和去初始化 284 ```c 285 /* WLAN芯片的初始化函数 */ 286 int32_t InitHi3881Chip(struct HdfWlanDevice *device) 287 { 288 uint8_t maxPortCount = 3; 289 int32_t ret = HI_SUCCESS; 290 uint8_t maxRetryCount = 3; 291 if (device == NULL || device->bus == NULL) { 292 HDF_LOGE("%s:NULL ptr!", __func__); 293 return HI_FAIL; 294 } 295 296 do { 297 if (ret != HI_SUCCESS) { 298 if (device->reset != NULL && device->reset->Reset != NULL) { 299 device->reset->Reset(device->reset); 300 } 301 HDF_LOGE("%s:Retry init hi3881!last ret=%d", __func__, ret); 302 } 303 ret = hi_wifi_init(maxPortCount, device->bus); 304 } while (ret != 0 && --maxRetryCount > 0); 305 306 if (ret != 0) { 307 HDF_LOGE("%s:Init hi3881 driver failed!", __func__); 308 return ret; 309 } 310 return HI_SUCCESS; 311 } 312 313 /* WLAN芯片的去初始化函数 */ 314 int32_t DeinitHi3881Chip(struct HdfWlanDevice *device) 315 { 316 (void)device; 317 int32_t ret = hi_wifi_deinit(); 318 if (ret != 0) { 319 HDF_LOGE("%s:Deinit failed!ret=%d", __func__, ret); 320 } 321 return ret; 322 } 323 ``` 324 - 芯片驱动的初始化和去初始化 325 ```c 326 /* WLAN芯片驱动挂接以及Mac80211与芯片侧的函数挂接 */ 327 static struct HdfChipDriver *BuildHi3881Driver(struct HdfWlanDevice *device, uint8_t ifIndex) 328 { 329 struct HdfChipDriver *specificDriver = NULL; 330 if (device == NULL) { 331 HDF_LOGE("%s fail: channel is NULL!", __func__); 332 return NULL; 333 } 334 (void)ifIndex; 335 specificDriver = (struct HdfChipDriver *)OsalMemCalloc(sizeof(struct HdfChipDriver)); 336 if (specificDriver == NULL) { 337 HDF_LOGE("%s fail: OsalMemCalloc fail!", __func__); 338 return NULL; 339 } 340 if (memset_s(specificDriver, sizeof(struct HdfChipDriver), 0, sizeof(struct HdfChipDriver)) != EOK) { 341 HDF_LOGE("%s fail: memset_s fail!", __func__); 342 OsalMemFree(specificDriver); 343 return NULL; 344 } 345 346 if (strcpy_s(specificDriver->name, MAX_WIFI_COMPONENT_NAME_LEN, HI3881_DRIVER_NAME) != EOK) { 347 HDF_LOGE("%s fail: strcpy_s fail!", __func__); 348 OsalMemFree(specificDriver); 349 return NULL; 350 } 351 specificDriver->init = Hi3881Init; 352 specificDriver->deinit = Hi3881Deinit; 353 354 HiMac80211Init(specificDriver); 355 356 return specificDriver; 357 } 358 359 /* 释放WLAN芯片驱动 */ 360 static void ReleaseHi3881Driver(struct HdfChipDriver *chipDriver) 361 { 362 if (chipDriver == NULL) { 363 return; 364 } 365 if (strcmp(chipDriver->name, HI3881_DRIVER_NAME) != 0) { 366 HDF_LOGE("%s:Not my driver!", __func__); 367 return; 368 } 369 OsalMemFree(chipDriver); 370 } 371 372 /* WLAN芯片驱动的初始化函数 */ 373 int32_t Hi3881Init(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice) 374 { 375 hi_u16 mode; 376 int32_t ret; 377 nl80211_iftype_uint8 type; 378 (void)chipDriver; 379 HDF_LOGI("%s: start...", __func__); 380 mode = wal_get_vap_mode(); 381 if (mode >= WAL_WIFI_MODE_BUTT) { 382 oam_error_log1(0, 0, "wal_init_drv_netdev:: invalid mode[%d]", mode); 383 return HI_FAIL; 384 } 385 if (mode == WAL_WIFI_MODE_STA) { 386 type = NL80211_IFTYPE_STATION; 387 #ifdef _PRE_WLAN_FEATURE_P2P 388 if (InitNetdev(netDevice, NL80211_IFTYPE_P2P_DEVICE) != HI_SUCCESS) { 389 return HI_FAIL; 390 } 391 #endif 392 } else if (mode == WAL_WIFI_MODE_AP) { 393 type = NL80211_IFTYPE_AP; 394 } else { 395 oam_error_log1(0, 0, "wal_init_drv_netdev:: invalid mode[%d]", mode); 396 return HI_FAIL; 397 } 398 ret = wal_init_drv_wlan_netdev(type, WAL_PHY_MODE_11N, netDevice); 399 if (ret != HI_SUCCESS) { 400 oam_error_log2(0, OAM_SF_ANY, "wal_init_drv_netdev %s failed.l_return:%d\n", netDevice->name, ret); 401 } 402 return ret; 403 } 404 405 /* WLAN芯片驱动的去初始化函数 */ 406 int32_t Hi3881Deinit(struct HdfChipDriver *chipDriver, struct NetDevice *netDevice) 407 { 408 int32_t ret; 409 (void)chipDriver; 410 ret = DeinitNetdev(NL80211_IFTYPE_P2P_DEVICE); 411 if (ret != HI_SUCCESS) { 412 oam_error_log1(0, OAM_SF_ANY, "Hi3881Deinit: DeinitNetdev p2p device fail, ret = %d\n", ret); 413 return ret; 414 } 415 return wal_deinit_drv_wlan_netdev(netDevice); 416 } 417 418 ``` 419 420 在芯片驱动初始化过程中调用netdev的init和add接口进行初始化netdev,并挂接netdev的一些函数指针。 421 422 ```c 423 hi_s32 wal_init_drv_wlan_netdev(nl80211_iftype_uint8 type, wal_phy_mode mode, oal_net_device_stru *netdev) 424 { 425 hi_char *ac_mode_str = NULL; 426 hi_s32 ret; 427 if (oal_unlikely(netdev == HI_NULL)) { 428 oam_error_log0(0, OAM_SF_ANY, "{netdev is null!}"); 429 return HI_ERR_CODE_PTR_NULL; 430 } 431 432 do { 433 /* 初始化网络设备。 */ 434 ret = wal_init_netdev(type, netdev); 435 if (ret != HI_SUCCESS) { 436 break; 437 } 438 439 ret = wal_init_netif(type, netdev); 440 if (ret != HI_SUCCESS) { 441 break; 442 } 443 ac_mode_str = "11bgn"; 444 if (mode == WAL_PHY_MODE_11G) { 445 ac_mode_str = "11bg"; 446 } else if (mode == WAL_PHY_MODE_11B) { 447 ac_mode_str = "11b"; 448 } 449 450 ret = wal_ioctl_set_mode(netdev, ac_mode_str); 451 } while (false); 452 453 if (ret != HI_SUCCESS) { 454 wal_deinit_wlan_vap(netdev); 455 oal_net_unregister_netdev(netdev); 456 oal_net_clear_netdev(netdev); 457 return HI_FAIL; 458 } 459 460 return HI_SUCCESS; 461 } 462 463 /* 挂接netdev的一些函数指针,详细挂接函数请参考NetDeviceInterFace */ 464 oal_net_device_ops_stru g_wal_net_dev_ops = 465 { 466 .getStats = wal_netdev_get_stats, 467 .open = wal_netdev_open, 468 .stop = wal_netdev_stop, 469 .xmit = hmac_bridge_vap_xmit, 470 .ioctl = wal_net_device_ioctl, 471 .changeMtu = oal_net_device_change_mtu, 472 .init = oal_net_device_init, 473 .deInit = oal_net_free_netdev, 474 475 ...... 476 477 }; 478 479 hi_s32 wal_init_netif(nl80211_iftype_uint8 type, oal_net_device_stru *netdev, const oal_wireless_dev *wdev) 480 { 481 /* 添加网络设备到协议栈 */ 482 hi_u32 ret = NetDeviceAdd(netdev, (Protocol80211IfType)type); 483 484 ...... 485 486 return HI_SUCCESS; 487 } 488 ``` 489 4903. 命令下发绑定,包括具有公共能力的设置MAC地址、设置发射功率等;STA相关的连接、扫描等;AP相关的启动AP、设置国家码等。 491 492 ```c 493 /* 驱动需要实现的MAC层基本能力的控制接口 */ 494 static struct HdfMac80211BaseOps g_baseOps = { 495 .SetMode = WalSetMode, 496 .AddKey = WalAddKey, 497 .DelKey = WalDelKey, 498 .SetDefaultKey = WalSetDefaultKey, 499 .GetDeviceMacAddr = WalGetDeviceMacAddr, 500 .SetMacAddr = WalSetMacAddr, 501 .SetTxPower = WalSetTxPower, 502 .GetValidFreqsWithBand = WalGetValidFreqsWithBand, 503 .GetHwCapability = WalGetHwCapability 504 }; 505 506 /* 驱动需要实现的MAC层STA能力的控制接口 */ 507 static struct HdfMac80211STAOps g_staOps = { 508 .Connect = WalConnect, 509 .Disconnect = WalDisconnect, 510 .StartScan = WalStartScan, 511 .AbortScan = WalAbortScan, 512 .SetScanningMacAddress = WalSetScanningMacAddress, 513 }; 514 515 /* 驱动需要实现的MAC层AP能力的控制接口 */ 516 static struct HdfMac80211APOps g_apOps = { 517 .ConfigAp = WalConfigAp, 518 .StartAp = WalStartAp, 519 .StopAp = WalStopAp, 520 .ConfigBeacon = WalChangeBeacon, 521 .DelStation = WalDelStation, 522 .SetCountryCode = WalSetCountryCode, 523 .GetAssociatedStasCount = WalGetAssociatedStasCount, 524 .GetAssociatedStasInfo = WalGetAssociatedStasInfo 525 }; 526 527 static struct HdfMac80211P2POps g_p2pOps = { 528 .RemainOnChannel = WalRemainOnChannel, 529 .CancelRemainOnChannel = WalCancelRemainOnChannel, 530 .ProbeReqReport = WalProbeReqReport, 531 .AddIf = WalAddIf, 532 .RemoveIf = WalRemoveIf, 533 .SetApWpsP2pIe = WalSetApWpsP2pIe, 534 .GetDriverFlag = WalGetDriverFlag 535 }; 536 537 /* 初始化Mac80211与芯片侧的函数挂接 */ 538 void HiMac80211Init(struct HdfChipDriver *chipDriver) 539 { 540 if (chipDriver == NULL) { 541 HDF_LOGE("%s:input is NULL!", __func__); 542 return; 543 } 544 chipDriver->ops = &g_baseOps; 545 chipDriver->staOps = &g_staOps; 546 chipDriver->apOps = &g_apOps; 547 chipDriver->p2pOps = &g_p2pOps; 548 } 549 ``` 550 5514. 事件上报接口调用,WLAN框架提供了event事件的上报接口,详情见hdf_wifi_event.c,例:调用HdfWiFiEventNewSta AP上报新关联的某个STA的情况。 552 553 ```c 554 hi_u32 oal_cfg80211_new_sta(oal_net_device_stru *net_device, const hi_u8 *mac_addr, hi_u8 addr_len, 555 oal_station_info_stru *station_info, oal_gfp_enum_uint8 en_gfp) 556 { 557 #if (_PRE_OS_VERSION_LINUX == _PRE_OS_VERSION) && !defined(_PRE_HDF_LINUX) 558 cfg80211_new_sta(net_device, mac_addr, station_info, en_gfp); 559 hi_unref_param(addr_len); 560 #elif (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION) || defined(_PRE_HDF_LINUX) 561 struct StationInfo info = { 0 }; 562 info.assocReqIes = station_info->assoc_req_ies; 563 info.assocReqIesLen = station_info->assoc_req_ies_len; 564 HdfWifiEventNewSta(net_device, mac_addr, WLAN_MAC_ADDR_LEN, &info); 565 hi_unref_param(en_gfp); 566 hi_unref_param(addr_len); 567 #endif 568 569 return HI_SUCCESS; 570 } 571 ``` 572**调测验证** 573 574驱动开发完成后,在WLAN模块单元测试里面开发自测试用例以及验证WLAN模块基本功能。测试环境采用开发者自测试平台(这里以Hi3516DV300标准系统为例)。 575 5761. 测试验证环境准备。 577 578 - 新建hostapd.conf文件(启动AP配置文件)并将以下内容复制到该文件中。 579 580 ```text 581 interface=wlan0 582 driver=hdf wifi 583 ctrl_interface=udp 584 #WiFi名称 585 ssid=test 586 hw_mode=g 587 channel=1 588 ignore_broadcast_ssid=0 589 wpa=2 590 rsn_pairwise=CCMP 591 # WiFi密码 592 wpa_passphrase=12345678 593 ``` 594 595 - 新建wpa_supplicant.conf文件(启动STA配置文件)并将以下内容复制到该文件中。 596 597 ```text 598 country=GB 599 600 network={ 601 #热点名称 602 ssid="test" 603 #热点密码 604 psk="12345678" 605 } 606 ``` 607 608 - 新建dhcpc.sh文件(将UDHCPC分配的IP地址等写入到设备中)并将以下内容复制到该文件中。 609 610 ```shell 611 #!/system/bin/sh 612 [ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1 613 614 RESOLV_CONF="/etc/resolv.conf" 615 [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" 616 [ -n "$subnet" ] && NETMASK="netmask $subnet" 617 618 case "$1" in 619 deconfig) 620 /system/bin/ifconfig $interface 0.0.0.0 621 ;; 622 623 renew|bound) 624 /system/bin/ifconfig $interface $ip $BROADCAST $NETMASK 625 626 if [ -n "$router" ] ; then 627 echo "deleting routers" 628 while busybox route del default gw 0.0.0.0 dev $interface ; do 629 : 630 done 631 632 for i in $router ; do 633 busybox route add default gw $i dev $interface 634 done 635 fi 636 637 echo -n > $RESOLV_CONF 638 [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF 639 for i in $dns ; do 640 echo adding dns $i 641 echo nameserver $i >> $RESOLV_CONF 642 done 643 ;; 644 esac 645 646 exit 0 647 ``` 648 649 - 新建udhcpd.conf文件(启动UDHCPD配置文件)并将以下内容(其中opt dns x.x.x.x x.x.x.x配置了两个DNS服务器地址,开发者可按照实际情况自行配置)复制到该文件中。 650 651 ```text 652 start 192.168.12.2 653 end 192.168.12.100 654 interface wlan0 #default: eth0 655 max_leases 20 #default: 254 656 remaining yes #default: yes 657 auto_time 7200 #default: 7200 (2 hours) 658 decline_time 3600 #default: 3600 (1 hour) 659 conflict_time 3600 #default: 3600 (1 hour) 660 offer_time 60 #default: 60 (1 minute) 661 min_lease 60 #defult: 60 662 lease_file /vendor/etc/udhcpd.leases 663 opt dns x.x.x.x x.x.x.x 664 option subnet 255.255.255.0 665 opt router 192.168.12.1 666 ``` 667 668 - 执行下列命令将测试所需文件推送到开发板。 669 670 ```shell 671 hdc shell "mount -o rw,remount /" 672 timeout /T 1 673 hdc file send dhcpc.sh /system/lib/ 674 hdc shell "chmod 777 /system/lib/dhcpc.sh" 675 hdc file send wpa_supplicant.conf / 676 hdc shell "mount -o rw,remount /vendor" 677 hdc file send hostapd.conf / 678 hdc file send udhcpd.conf /vendor/etc 679 hdc shell "touch /vendor/etc/udhcpd.leases" 680 hdc shell "chmod 777 /vendor/etc/udhcpd.leases" 681 ``` 682 6832. 验证WiFi基本功能。 684 685 - 验证AP基本功能 686 687 1. 开发板启动AP,测试终端(例如手机)打开WiFi开关(设置 -> WLAN -> 打开WiFi开关)。 688 689 2. 使用cmd窗口输入如下命令。 690 ```shell 691 hdc shell 692 hostapd ./hostapd.conf 693 ``` 694 695 3. 使用另一个cmd窗口执行下列命令。 696 697 ```shell 698 hdc shell 699 ifconfig wlan0 192.168.12.1 netmask 255.255.255.0 700 busybox udhcpd /vendor/etc/udhcpd.conf 701 ``` 702 703 4. 在手机的WiFi列表中找到对应名称为test的网络,并输入密码(网络名称及密码均在在hostapd.conf中进行配置,成功连接后,手机上可看到已连接)。 704 705 5. 使用开发板ping测试终端。 706 707 ```shell 708 busybox ping xxx.xxx.xxx.xxx 709 ``` 710 711 上述xxx.xxx.xxx.xxx为当前测试终端的IP地址,若测试能够ping通测试终端则表示,WLAN驱动基本功能正常。 712 713 - 验证STA基本功能 714 715 1. 开发板启动STA,测试终端(例如手机)打开热点(网络名称及密码均在在hostapd.conf中进行配置,热点名称为test,密码为12345678)。 716 717 2. 使用cmd窗口输入如下命令。 718 719 ```shell 720 hdc shell 721 wpa_supplicant -i wlan0 -d -c wpa_supplicant.conf 722 ``` 723 724 3. 使用另一个cmd窗口执行下列命令。 725 726 ```shell 727 hdc shell 728 mount -o rw,remount / 729 mount -o rw,remount /vendor 730 busybox udhcpc -i wlan0 -s system/lib/dhcpc.sh 731 ``` 732 上述命令执行成功后,回显信息中可以看到单板及测试终端IP地址。 733 734 4. 使用开发板ping测试终端。 735 736 ```shell 737 busybox ping xxx.xxx.xxx.xxx 738 ``` 739 740 上述xxx.xxx.xxx.xxx为当前测试终端的IP地址,若测试能够ping通测试终端则表示,WLAN驱动基本功能正常。 741 742#### 接口调用 743WLAN驱动模块向上层提供两种能力接口:HDI接口和HAL接口。 744- HDI接口调用 745 746 HDI接口调用开发步骤(以GetSupportFeature为例): 747 748 1. 使用WlanInterfaceGetInstance获取WLAN服务对象。 749 750 2. 使用Start创建HAL和驱动之间的通道及获取驱动网卡信息。 751 752 3. 通过GetSupportFeature获取该设备支持的WLAN特性。 753 754 4. 调用Stop,销毁HAL和驱动之间的通道。 755 756 5. 执行WlanInterfaceRelease销毁WLAN服务对象。 757 758 HDI接口调用开发实例: 759 ```c 760 #include "v1_0/iwlan_interface.h" 761 #include "wlan_callback_impl.h" 762 #include "wlan_impl.h" 763 764 #define PROTOCOL_80211_IFTYPE_NUM 11 765 #define HDF_SUCCESS 0 766 #define HDF_FAILURE (-1) 767 768 static int32_t hdi_main() 769 { 770 int32_t rc; 771 const char *WLAN_SERVICE_NAME = "wlan_hal_c_service"; 772 static struct IWlanInterface *g_wlanObj = NULL; 773 uint8_t supType[PROTOCOL_80211_IFTYPE_NUM + 1] = {0}; 774 uint32_t supTypeLen = PROTOCOL_80211_IFTYPE_NUM + 1; 775 776 /* 获取WLAN服务对象。*/ 777 g_wlanObj = WlanInterfaceGetInstance(WLAN_SERVICE_NAME); 778 if (g_wlanObj == NULL) 779 { 780 return HDF_FAILURE; 781 } 782 783 /* 创建HAL和驱动之间的通道及获取驱动网卡信息。 */ 784 rc = g_wlanObj->Start(g_wlanObj); 785 if (rc != HDF_SUCCESS) 786 { 787 return HDF_FAILURE; 788 } 789 790 /* 获取该设备支持的WLAN特性(不考虑当前的使用状态)。 */ 791 rc = g_wlanObj->GetSupportFeature(g_wlanObj, supType, &supTypeLen); 792 if (rc != HDF_SUCCESS) 793 { 794 return HDF_FAILURE; 795 } 796 797 /* 销毁HAL和驱动之间的通道。 */ 798 rc = g_wlanObj->Stop(g_wlanObj); 799 if (rc != HDF_SUCCESS) 800 { 801 return HDF_FAILURE; 802 } 803 804 /* 销毁WLAN服务对象。 */ 805 rc = WlanInterfaceRelease(g_wlanObj); 806 if (rc != HDF_SUCCESS) 807 { 808 return HDF_FAILURE; 809 } 810 return rc; 811 } 812 813 ``` 814 815 HDI接口调用编译: 816 817 1. 编译脚本中添加依赖的库文件: 818 819 ```text 820 deps = [ 821 "//drivers/peripheral/wlan/hdi_service:hdi_wlan_service", 822 ] 823 ``` 824 2. 编译脚本中添加依赖的头文件: 825 ```text 826 include_dirs = [ 827 "//drivers/peripheral/wlan/interfaces/include", 828 "//drivers/peripheral/wlan/hdi_service", 829 "//drivers/peripheral/wlan/client/include", 830 "//drivers/peripheral/wlan/hal/include", 831 ] 832 ``` 833 3. 执行编译脚本,确认是否编译OK。 834 835- HAL接口调用 836 837 HAL接口调用开发步骤(需要测试HAL模块指定接口时,可采用下列步骤): 838 839 1. 使用WifiConstruct创建一个WiFi实体。 840 841 2. 用创建的WiFi实体调用start开启HAL和驱动之间的通道,获得驱动网卡的信息。 842 843 3. 通过createFeature创建一个apFeature或者staFeature。后面可通过这些Feature去调用具体的实现接口,下面基于创建的apFeature为例进行介绍。 844 845 4. 调用和使用相关接口:如setMacAddress设置MAC地址、getDeviceMacAddress获取设备的MAC地址等。 846 847 5. 调用destroyFeature,销毁掉创建的apFeature。 848 849 6. 调用stop销毁创建的通道。 850 851 7. 执行WifiDestruct销毁创建的WiFi实体。 852 853 HAL接口调用开发实例: 854 855 ```c 856 #include "wifi_hal.h" 857 #include "wifi_hal_sta_feature.h" 858 #include "wifi_hal_ap_feature.h" 859 #include "wifi_hal_cmd.h" 860 861 #define MAC_LEN 6 862 #define HDF_SUCCESS 0 863 #define HDF_FAILURE (-1) 864 865 static int32_t hal_main() 866 { 867 int32_t ret; 868 struct IWiFi *wifi; 869 struct IWiFiAp *apFeature; 870 871 /* 创建一个wifi实体。 */ 872 ret = WifiConstruct(&wifi); 873 if (ret != HDF_SUCCESS || wifi == NULL) { 874 return HDF_FAILURE; 875 } 876 877 /* 开启HAL和驱动之间的通道,获得驱动网卡的信息。 */ 878 ret = wifi->start(wifi); 879 if (ret != HDF_SUCCESS) { 880 return HDF_FAILURE; 881 } 882 883 /* 创建apFeature。 */ 884 ret = wifi->createFeature(PROTOCOL_80211_IFTYPE_AP, (struct IWiFiBaseFeature **)&apFeature); 885 if (ret != HDF_SUCCESS) { 886 return HDF_FAILURE; 887 } 888 889 /* 获取设备MAC地址。 */ 890 unsigned char mac[MAC_LEN] = {0}; 891 ret = apFeature->baseFeature.getDeviceMacAddress((struct IWiFiBaseFeature *)apFeature, mac, MAC_LEN); 892 if (ret != HDF_SUCCESS) { 893 return HDF_FAILURE; 894 } 895 896 /* 销毁创建的apFeature。 */ 897 ret = wifi->destroyFeature((struct IWiFiBaseFeature *)apFeature); 898 if (ret != HDF_SUCCESS) { 899 return HDF_FAILURE; 900 } 901 902 /* 销毁HAL和驱动之间的通道。 */ 903 ret = wifi->stop(wifi); 904 if (ret != HDF_SUCCESS) { 905 return HDF_FAILURE; 906 } 907 908 /* 销毁创建的WiFi实体。 */ 909 ret = WifiDestruct(&wifi); 910 if (ret != HDF_SUCCESS) { 911 return HDF_FAILURE; 912 } 913 return ret; 914 } 915 ``` 916 HAL接口调用编译: 917 1. 编译脚本中添加依赖的库文件: 918 919 ```text 920 deps = [ 921 "//drivers/peripheral/wlan/client:wifi_driver_client", 922 "//drivers/peripheral/wlan/hal:wifi_hal", 923 ] 924 ``` 925 926 2. 编译脚本中添加依赖的头文件: 927 ```text 928 include_dirs = [ 929 "//drivers/peripheral/wlan/interfaces/include", 930 "//drivers/peripheral/wlan/hdi_service", 931 "//drivers/peripheral/wlan/client/include", 932 "//drivers/peripheral/wlan/hal/include", 933 ] 934 ``` 935 3. 执行编译脚本,确认是否编译OK。 936 937 938 939 940## 参考 941 942- 代码仓库如下: 943 944 **[drivers\_hdf\_core](https://gitee.com/openharmony/drivers_hdf_core)** 945 946 [drivers\_peripheral](https://gitee.com/openharmony/drivers_peripheral) 947 948 [drivers\_interface](https://gitee.com/openharmony/drivers_interface) 949 950- 代码路径如下: 951 952 WLAN模块流控组件liteos适配://drivers/hdf_core/adapter/khdf/liteos/model/network/wifi 953 954 HDF网络模型liteos适配://drivers/hdf_core/adapter/khdf/liteos/model/network 955 956 WLAN模块流控组件Linux适配、HDF WLAN模型、VENDOR WLAN驱动编译: 957 958 //drivers/hdf_core/adapter/khdf/linux/model/network/wifi 959 960 WLAN模块实现核心代码://drivers/hdf_core/framework/model/network/wifi 961 962 WLAN模块对外接口://drivers/hdf_core/framework/include/wifi 963 964 HDF网络模型接口://drivers/hdf_core/framework/include/net 965 966 WLAN HDI服务端实现://drivers/peripheral/wlan 967 968