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