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![image](figures/WLAN驱动接口框架图.png "WLAN框架图")
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&nbsp;AddFeature(struct&nbsp;WifiModule&nbsp;\*module,&nbsp;uint16_t&nbsp;featureType,<br>&nbsp;struct&nbsp;WifiFeature&nbsp;\*featureData) | 基于HDF开发WLAN驱动时,注册一个功能组件到WifiModule。 |
125
126    **表5** wifi_mac80211_ops.h
127
128  | 接口名称 | 功能描述 |
129  | -------- | -------- |
130  | int32_t&nbsp;(\*startAp)(NetDevice&nbsp;\*netDev) | 启动AP。 |
131  | int32_t&nbsp;(\*stopAp)(NetDevice&nbsp;\*netDev) | 停止AP。 |
132  | int32_t&nbsp;(\*connect)(NetDevice&nbsp;\*netDev,&nbsp;WifiConnectParams&nbsp;\*param) | 开始关联。 |
133  | int32_t&nbsp;(\*disconnect)(NetDevice&nbsp;\*netDev,&nbsp;uint16_t&nbsp;reasonCode) | 取消关联。 |
134
135    **表6** hdf_netbuf.h
136
137  | 接口名称 | 功能描述 |
138  | -------- | -------- |
139  | static&nbsp;inline&nbsp;void&nbsp;NetBufQueueInit(struct&nbsp;NetBufQueue&nbsp;\*q) | 初始化NetBuf队列。 |
140  | struct&nbsp;NetBuf&nbsp;\*NetBufAlloc(uint32_t&nbsp;size) | 申请NetBuf。 |
141  | void&nbsp;NetBufFree(struct&nbsp;NetBuf&nbsp;\*nb) | 释放NetBuf。 |
142  | struct&nbsp;NetBuf&nbsp;\*Pbuf2NetBuf(const&nbsp;struct&nbsp;NetDevice&nbsp;\*netdev,&nbsp;struct&nbsp;pbuf&nbsp;\*lwipBuf) | lwip的pbuf转换为NetBuf。 |
143  | struct&nbsp;pbuf&nbsp;\*NetBuf2Pbuf(const&nbsp;struct&nbsp;NetBuf&nbsp;\*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/wifi158
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